3

I want to confirm what I think I understand about the lifetime of objects which have been push_back()'ed on an std::vector. What I read says that the elements in the vector are copies. So, is the usage below OK? Specifically, is the variable s in f2() a different instance of an std::string than the one that is push_back()'ed in f1(), and thus safe to use?

void f1(std::vector<std::string>* pv) {
    std::string s = "hi";               
    pv->push_back(s);
}

void f2(void) {
    std::vector<std::string> v;
    f1(&v);
    for (size_t i = 0; i < v.size(); ++i) {
        std::string s = v.at(i);
        std::cout << s;
    }
}
leiyc
  • 903
  • 11
  • 23
John Fitzpatrick
  • 4,207
  • 7
  • 48
  • 71
  • 2
    Yes, code is correct. And vector is safe, because string in vector is another object than you pushed in. – George Gaál Aug 14 '11 at 05:38
  • 3
    Yes it is. But why on Earth are you using that raw pointer? That is more concerning. – johnsyweb Aug 14 '11 at 06:07
  • @Johnsyweb: What's wrong with the pointer usage in the question? – CB Bailey Aug 14 '11 at 07:39
  • 1
    I think what you're concerned about is *lifetime*, not *scope*. A name's scope is the region of program text in which it's visible. An object's lifetime is the span of time (during program execution) during which it exists. – Keith Thompson Aug 14 '11 at 08:22
  • 1
    @Charles Bailey: Would you not rather pass the `vector` by reference and reduce the risk of invalid pointers, NULLs, et cetera? – johnsyweb Aug 14 '11 at 08:36
  • 1
    OK. I get it. References are preferred to pointers. I've been using C since the 80's and old habits die hard. I only work in real C++ from time to time. To be honest, I always thought references were introduced just to allow us to type one character "." for accessing a member instead of two "->". But now that Charles points it out (pun intended), I think I can see how reference usage would protect me from NULL and invalid pointers. Finally a real reason to use them! (And yes, Keith, I meant "lifetime" not scope, thanks. I edited the question to reflect that.) – John Fitzpatrick Aug 14 '11 at 09:35
  • @Johnsyweb: I would, yes, but I frequently code in codebases which avoid all non-`const` reference parameters because they prefer to see an explicit "address of" when passing things to functions that might modify parameters. It's an older - but IMHO perfectly understandable - convention. – CB Bailey Aug 14 '11 at 10:01

4 Answers4

4

Yes that is correct. A copy of string s gets stored during push_back. Check the doccumentation for detail. It states:

void push_back ( const T& x );

Adds a new element at the end of the vector, after its current last element. The content of this new element is initialized to a copy of x.

Parameters
x
Value to be copied to the new element.
T is the first template parameter (the type of the elements stored in the vector).

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • I agree about a vector's behavior, but since `push_back`'s parameter is a reference, how is it that the argument is copied? Does `push_back` actually receive its argument by reference, and the implementation of `push_back` makes the copy? – ybakos May 01 '12 at 12:42
  • 1
    @ybakos: Yes, `push_back` itself makes the copy. – Alok Save May 01 '12 at 14:10
4
std::string s = "hi";               
pv->push_back(s);

Note that this is unnecessarily inefficient. Since s is an lvalue, push_back will indeed make a copy. If you say pv->push_back(std::string("hi")) instead, a C++0x compiler can replace the copy with a move, because std::string("hi") is an rvalue. You could even say:

pv->emplace_back("hi");

to construct the string object in place. No copy or move necessary.

Community
  • 1
  • 1
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
1

When a push_back operation in the above, it does make a copy of string s. So, it is safe.

Mahesh
  • 34,573
  • 20
  • 89
  • 115
0

Yes it is correct. The string s will be copied.

However there is one interesting thing about how the class string is usually implemented that is valuable to mention. If you create a new string from another string or from a const char pointer it does not at first copy all the characters to its internal array, but uses a pointer to the source data. Only when you want to modify the string (or the source string is modified) an actual copy of characters array is created. So effectively string instances share characters data if it is not modified.

In case of your code, pushing back s will copy an instance of string, but will not copy the characters "hi", so this will be relatively fast.

EDIT:

as others noted this copy-on-write string optimization is no longer common nowadays so nevermind ;) here's some information why this is the case

Community
  • 1
  • 1
ciamej
  • 6,918
  • 2
  • 29
  • 39
  • 2
    Copy-on-write is not guaranteed for C++03 and is forbidden to implementations of `std::string` (`basic_string`, really) for C++0x. – Luc Danton Aug 14 '11 at 06:28
  • 2
    Not guaranteed, and not the least bit common either. – Benjamin Lindley Aug 14 '11 at 06:30
  • 2
    -1: Not guaranteed, not common, forbidden by C++0x, and a _terrible_ idea if you like threading (hence being forbidden by C++0x). In short, wrong. – Nicol Bolas Aug 14 '11 at 07:08
  • didn't know it's forbidden in C++0x, but I remember I have read years ago about it in a book "The C++ Standard Library" by Nicolai M. Josuttis or maybe it was Bjarne Stroustroup's C++ Language? could you please tell me why is it forbidden in C++0x, it seemed to be a reasonable idea... – ciamej Aug 14 '11 at 07:14
  • besides I have never written that it is guaranteed, I only wrote that it is usually implemented this way, I was wrong, but it used to be common in the past and in the sole begining the string class was designed in a such way to allow this optimization, the gcc's (libstdc++) string class was doing it at least until 2009 or so, so I guess saying "not the least bit common" is not really acurrate – ciamej Aug 14 '11 at 07:34
  • I just ran a test on my cygwin g++ and actually std::string supports COW, not sure how it looks like in newer versions, mine is outdated, that might be worth checking, however I believe that it is still the case unless you compile specifically C++0x – ciamej Aug 14 '11 at 07:59
  • gcc is still doing COW because they can not break the API of libstdc++. It is highly likely to change in the next revision. – Bo Persson Aug 14 '11 at 08:38