2

So I have the following code:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main() {
    vector<string> strs;
    strs.push_back("happy");    
    const string& a1 = strs[0];
    strs.push_back("birthday");
    const string& a2 = strs[1];
    strs.push_back("dude");
    const string& a3 = strs[2];

    printf("%s\n", a1.c_str());     
    return 0;
}

which is pretty straightforward but it doesn't work. The printf doesn't print anything. It does print if I change it to:

const string& a1 = strs[0].c_str();

can someone please explain the behavior of it.

Bob Sacamano
  • 699
  • 15
  • 39
  • 3
    Read the doc on [`push_back`](http://en.cppreference.com/w/cpp/container/vector/push_back), particularly the part about : "If the new `size()` is greater than `capacity()` then all iterators **and references** (including the past-the-end iterator) are invalidated." – WhozCraig May 24 '15 at 16:41
  • 1
    If you don't want your references to be invalidated, reserve space in advance, e.g. `strs.reserve(16); // reserve space for 16 elements`. – vsoftco May 24 '15 at 16:47

2 Answers2

8

Your calls to push_back potentially (and in your case obviously actually) invalidate all references into the vector, namely if the vector is too small to store the new element. You thus cannot use any references into the vector created before a push_back unless you make sure that the vectors capacity is big enough.

If you make sure that the vector has enough capacity for all the elements (i.e. by using std::vector::reserve) before you create the references, your first version will work as expected.

Your second example works because you create a new, temporary string (which has its lifetime extended to the lifetime of the reference) the reference binds to.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
1
strs.push_back("happy");    
const string& a1 = strs[0];

Your reference is valid upto this point. The following push_back however creates problems

strs.push_back("birthday");

This increases the capacity of the vector from 1 to 2. Since the new capacity is greater than the old capacity, all references (as well as iterators) created uptill this point on the vector get invalidated.

As a side note, The c_str gives you a char* (\0 terminated string). If your insertion was of the form

strs.push_back("happ\0y");
const string& a1 = strs[0].c_str();

a1 would have the value 'happ'

Pranav Kapoor
  • 1,171
  • 3
  • 13
  • 32