Is it safe to push_back an element from the same vector?

Solution 1:

It looks like http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526 addressed this problem (or something very similar to it) as a potential defect in the standard:

1) Parameters taken by const reference can be changed during execution of the function

Examples:

Given std::vector v:

v.insert(v.begin(), v[2]);

v[2] can be changed by moving elements of vector

The proposed resolution was that this was not a defect:

vector::insert(iter, value) is required to work because the standard doesn't give permission for it not to work.

Solution 2:

Yes, it's safe, and standard library implementations jump through hoops to make it so.

I believe implementers trace this requirement back to 23.2/11 somehow, but I can't figure out how, and I can't find something more concrete either. The best I can find is this article:

http://www.drdobbs.com/cpp/copying-container-elements-from-the-c-li/240155771

Inspection of libc++'s and libstdc++'s implementations shows that they are also safe.

Solution 3:

The standard guarantees even your first example to be safe. Quoting C++11

[sequence.reqmts]

3 In Tables 100 and 101 ... X denotes a sequence container class, a denotes a value of X containing elements of type T, ... t denotes an lvalue or a const rvalue of X::value_type

16 Table 101 ...

Expression a.push_back(t) Return type void Operational semantics Appends a copy of t. Requires: T shall be CopyInsertable into X. Container basic_string, deque, list, vector

So even though it's not exactly trivial, the implementation must guarantee it will not invalidate the reference when doing the push_back.

Solution 4:

It is not obvious that the first example is safe, because the simplest implementation of push_back would be to first reallocate the vector, if needed, and then copy the reference.

But at least it seems to be safe with Visual Studio 2010. Its implementation of push_back does special handling of the case when you push back an element in the vector. The code is structured as follows:

void push_back(const _Ty& _Val)
    {   // insert element at end
    if (_Inside(_STD addressof(_Val)))
        {   // push back an element
                    ...
        }
    else
        {   // push back a non-element
                    ...
        }
    }