(Answer for C++17 only)
I believe that the correct answer is somewhere in between NathanOliver's (now deleted) answer and AndyG's answer.
As AndyG points out, such a guarantee cannot exist in general: sometimes, the library must actually perform a move construction just to determine whether or not the insertion can take place. This will be the case for the emplace
function, whose behaviour is specified by the standard as:
Effects: Inserts a value_type
object t
constructed with std::forward<Args>(args)...
if and only if there is no element in the container with key equivalent to the key of t
.
We can interpret this as saying that the object t
is constructed no matter what, and then is disposed of if the insertion cannot happen because the value t
or t.first
already exists in the set or map, respectively. And since the method template <class P> pair<iterator, bool> insert(P&&)
of std::map
is specified in terms of emplace
, as AndyG points out, it has the same behaviour. As SergeyA points out, the try_emplace
methods are designed to avoid this issue.
However, in the specific example given by the OP, the value being inserted is of exactly the same type as the container's value type. The behaviour of such an insert
call is specified by the general requirements paragraph previously given by NathanOliver:
Effects: Inserts t
if and only if there is no element in the container with key equivalent to the key of t
.
In this case, there no license is given for the library to modify the argument in the case where the insertion does not take place. I believe that calling a library function is not supposed to have any observable side effects besides what the standard explicitly allows. Thus, this case, t
must not be modified.