This question is about the specification of several functions in the C++11 Standard Library, that take their arguments as rvalue references, but do not consume them in all cases. One example is
std::unordered_set<T>::insert(T&&).
It is pretty clear, that this method will use the move constructor of T to construct the element within the container, if it does not already exist. However, what happens if the element already exists in the container? I am pretty sure there is no reason the change the object in the case. However, I didn’t find anything in the C++11 Standard supporting my claim.
Here is an example to show why this might be interesting. The following code reads lines from std::cin and remove the first occurrence of duplicate lines.
std::unordered_set<std::string> seen;
std::string line;
while (getline(std::cin, line)) {
bool inserted = seen.insert(std::move(line)).second;
if (!inserted) {
/* Is it safe to use line here, i.e. can I assume that the
* insert operation hasn't changed the string object, because
* the string already exists, so there is no need to consume it. */
std::cout << line << '\n';
}
}
Apparently, this example works with GCC 4.7. But I am not sure, if it is correct according to the standard.
I found this note in the standard (17.4.6.9):
While it doesn’t directly answer your question it does indicate that you’ve effectively “given” the argument to the library function as a temporary so I wouldn’t rely on its value once you’ve called
insert. As far as I can tell, a library implementation would be entitled to move from the parameter even if it subsequently determines that it isn’t going to keep the value in the container.