Pointer Arithmetic, Containers & Iterators

(see GitHub project PointerArithmeticAndIters for working code related to this topic.)

What?

The main rationale for this post is my terrible memory: every time I need to initialize a Standard Template Library in C++, I end up hitting Google.  Maybe writing this will shore up my memory,  but if not, at least searching for the answer should be easier.

What I need to do is define a list of strings of known values, and I’d rather not code this up as a sequence lines such as  foo.push_back(“my string”).

How?

From Google, it looks that the “range” constructor for list is what I need, illustrated by this sample from  the C++ Reference:

// the iterator constructor can also be used to construct from arrays:
  int myints[] = {16,2,77,29};
  std::list<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );

N.b., sizeof(myints) / sizeof(int) is 4.

This shows the answer as plainly as possible, but my mind recoiled.  If I had an array of four items, why would the “end” be only 4 bytes offset from myints, instead of 16 (for 32-bit ints) or 32 (for 64-bit ints)?

It took some time for me to recall that pointer arithmetic increments by the length of the item referenced by the pointer.  So that one be one if it’s a char, but 4 or 16 if it’s an int.  Put another way, for some array of ints or pointer to int called “myints”, the value of

myints + 7

…is the same as

&myints[7]

A corollary is that when using the Standard Template Library with C-style arrays, the type of the iterator of the array is a pointer to an array element.

So to initialize a Standard Template Library list of string, you might do something like this:

 std::string str_array[] =
 {
     std::string("mop"),
     std::string("bop"),
     std::string("a loo la"),
     std::string("mop"),
     std::string("bam"),
     std::string("boom!"), // Comma after last element is optional.
 }
 std::list<std::string> 
 my_list(str_array, 
         str_array + sizeof(str_array)/sizeof(str_array[0]));

With C++11, initialization can be much more elegant.  Using braces, you could declare and initialize a vector of string with something like this:

 std::vector<std::string> my_vec 
     {std::string("Good"), 
      std::string("Golly"), 
      std::string("Miss"), 
      std::string("Molly")};

Bonus: Template for Sequence Containers

In the GitHub project accompanying this post, I display the elements in a container.  Initially, there was an uncomfortable amount of replicated code to do this:  But by using templates, I was able to share the same iteration routine across sequence containers list, set, and vector:

template <typename ITER>
void printColl(std::string nm, ITER start, ITER end)
{
    std::cout << nm.c_str() << ": " << std::endl);
    for (ITER iter = start; iter != end; ++iter)
    {
        std::cout << "\t" << *iter << std::endl;
    }
    std::cout << std::endl;
 }
 ...
 printColl<std::list<std::string>::iterator> ("my_list", 
                                               my_list.begin(), 
                                               my_list.end());
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s