I have heard that one of the recommendations of Modern C++ is to use emplace_back
instead of push_back
for append in containers (emplace_back
accept any version of parameters of any constructor of the type storage in the container).
According to the standard draft N3797 23.3.6.5 (1), say that:
Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. If an exception is thrown by the move constructor of a non-CopyInsertable T, the effects are unspecified.
This specify what happen when no reallocation is needed, but leave open the problem when the container need to grow.
In this piece of Code:
#include <iostream>
#include <vector>
int main() {
std::vector<unsigned char> buff {1, 2, 3, 4};
buff.emplace_back(buff[0]);
buff.push_back(buff[1]);
for (const auto& c : buff) {
std::cout << std::hex << static_cast<long>(c) << ", ";
}
std::cout << std::endl;
return 0;
}
Compiled with VC++ (Visual Studio 2013 Update 4) and GCC 4.9.1 (MinGW) in Debug in Windows 8.1.
When compiled with VC++ the output is:
1, 2, 3, 4, dd, 2
When compiled with GCC the output is:
1, 2, 3, 4, 1, 2
Checking the implementation of emplace_back
in VC++ the difference is that the first lines of code, check if the container need to grow (and grow if it's needed), in the case that the container need to grow, the reference to the first element (buff[0]) received in the emplace_back
method is invalidated and when the actual setting of the value in the new created element of the container happen the value is invalid.
In the case of the push_back
work because the creation of the element to append is made in the parameter binding (before the possible grow of the container).
My question is:
This behavior, when the container need to grow because a call to emplace_back
and the parameter is a reference to the same container is implementation defined, unspecified or there is a problem in the implementation of one of the compiler (suppose in VC++ as GCC behavior is more close to the expected)?