You are here:

C++/Vector operation

Advertisement


Question
Hi Mr, McArdell,

I am bginning in C++ and tries to get my hands at understanding how to manipulate vector. Most examples I have seen discuss 2D or 3D vector. They are built in a class and each functions process each datapoint (x,y,z) discretely. I want to handle a large vector and do some (one) operation with two different vector of the same size. Here is my code.

/********************************************************************************************
*                                                                      *
*  This is a test program to calculate relative values. A numerator vector contains the    *
*  the price data of a stock. The denominator vector contains the price data of an index.  *
*  by dividing each vector items of numerator by the corresponding vector item of          *
*  denominator, you end up with the relative performance of the stock.                     *
*                                                                      *
********************************************************************************************/

#include <iostream>
#include <vector>

using namespace std;
typedef vector<double> Vec;
typedef Vec::iterator Vit;

int g;

void print(Vec v)
{
   for (Vit it = v.begin(); it != v.end(); it++)
      cout << *it << ", ";
   cout << endl;
}

Vec relativeTo(const Vec& a, Vec& b)
{
   Vec RelVec;
   for(size_t i = 0; i < a.size(); i++)
     RelVec[i]= a[i] / b[i];
   return RelVec;
}

int main()
{
  Vec aaa;
  Vec bbb;

  // add random values to the vector
  aaa.push_back(1.0);
  aaa.push_back(2.0);
  aaa.push_back(41.0);
  aaa.push_back(54.0);

  bbb.push_back(3.0);
  bbb.push_back(7.0);
  bbb.push_back(24.0);
  bbb.push_back(77.0);

  // Print back the vector data points
  cout << "\nVector aaa: ";
  print(aaa);
  cout << "\nVector bbb: ";
  print(bbb);
  cout << " aaa relative to bbb: ";
  print(relativeTo(aaa, bbb));
  
  cin >> g;

  return 0;
}

This compiles fine but I get a subscript out of range at print(relativeTo(aaa,bbb)); The problem line is in the relativeTo function where I have RelVec[i] = a[i] / b[i]; I thought that by using a.size() the program could not get outside the vector. I am at a lost to understand where the error comes from. Any help, pointers or direction is appreciated. Thanks for your time.  Eric.

Answer
OK, let us run through this shall we.

The line in question references 3 vectors: a, b and RelVec.

The a and b vectors are references to vectors passed into the relativeTo function.
(query: why is only parameter a specified as reference to _const_ Vec?)

You iterate from zero to less than (element) size of a.
Is there any guarantee that b is of the same or greater size?
How many elements does the newly created local RelVec contain?

This last is your problem.
You have forgotten that standard vector type instances are created empty and you have to use push_back to append new elements to a vector - as you do in main for aaa and bbb:

       RelVec.push_back(a[i] / b[i]);

Oh, just so you know I thought I would mention that in this case we can use pre-defined parts of the C++ standard library to do the heavy lifting for us. For example consider the following version of relativeTo:

   Vec relativeTo(const Vec& a, const Vec& b)
    {
        Vec RelVec;
        std::transform( a.begin(), a.end()
                      , b.begin()
                      , std::back_inserter(RelVec)
                      , std::divides<double>()
                      );
        return RelVec;
    }

You will have too add the following includes:

   #include <algorithm>  // for std::transform
   #include <iterator>   // for std::back_inserter
   #include <functional> // for std::divides

The std::transform algorithm can transform two input ranges into one output range applying a function (or functor) to each pair of elements and outputting the result to the output range. The std::back_inserter function creates an iterator adapter that calls push_back on the passed collection rather than just writing into existing elements. and std::divides provides a function-like interface around the division operator so it can be used in situations like this. For more information I suggest you look at a decent text on the C++ standard library such as "The C++ Standard Library a Tutorial and Reference" by Nicolai M. Josuttis (highly recommended by the way).

One final point: The canonical forms of post increment (as you use in print) and decrement for user defined types are _less_ efficient than their pre-increment forms. In fact they are usually defined in terms of the pre-increment (or decrement) operations:

   class MyClass
   {
   // ...
       MyClass & operator++();     // 1
       MyClass   operator++(int);  // 2
   };

   MyClass MyClass::operator++(int)
   {
       MyClass tmp(*this);         // 3
       
       ++*this                     // 4
       
       return tmp;                 // 5
   }

We have a class - MyClass that implements pre-increment (declared at 1) and post increment (declared at 2). Notice that for pre-increment we return the value by reference - typically *this. For post-increment we return by _value_ - typically this is more expensive.

In the implementation of the post-increment operation at 3 we first save the current state of the object, then at 4 increment the object using the pre-increment operation (definition not shown) then at 5 return - by value, as previously noted - the saved copy of the object holding its previous state.

Hence where it does not matter C++ people prefer to use pre-increment and decrement - especially for user defined types such as iterators for containers as used in the for loop for your print function:

    for (Vit it = v.begin(); it != v.end(); it++)

Thus prefer ++it:

    for (Vit it = v.begin(); it != v.end(); ++it)

(OK sometimes iterators may be defined as simple pointers but not always).

Hope this helps.

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2012 About.com, a part of The New York Times Company. All rights reserved.