Reputation: 153967
What happens if to a movable object if I call
std::set<>::insert
on it, and the insertion doesn't take place
because there is already an object with the same key present in
the set. In particular, is the following valid:
struct Object
{
std::string key;
// ...
struct OrderByKey
{
bool operator()( Object const& lhs, Object const& rhs) const
{
return lhs.key < rhs.key;
}
};
Object( Object&& other )
: key(std::move(other.key))
// ...
{
}
};
and:
std::set<Object, Object::OrderByKey> registry;
void
register(Object&& o)
{
auto status = registry.insert(std::move(o));
if (!status.second)
throw std::runtime_error("Duplicate entry for " + o.key);
}
After the registry.insert
, when no insertion takes place, has
o
been moved or not. (If it might have been moved, I need to
save a copy of the string before hand, in order to use it in the
error message. (And yes, I know that I can always write:
throw std::runtime_error( "Duplicate entry for " + status->first.key );
Which is what I'll probably do. But I would still like to know what the standard says about this.)
Upvotes: 15
Views: 685
Reputation: 12907
Well, to answer your last question
I would still like to know what the standard says about this
the standard specifies what happen with insert(t)
in Table 102 - Associative container requirements
, p717 of N3376 (emphasis mine):
Requires: If t is a non-const rvalue expression, value_type shall be MoveInsertable into X; otherwise, value_type shall be CopyInsertable into X.
Effects: Inserts t if and only if there is no element in the container with key equivalent to the key of t. The bool component of the returned pair is true if and only if the insertion takes place, and the iterator component of the pair points to the element with key equivalent to the key of t.
so I'd say that nothing should happen and that your Object
is still valid and not unspecified state.
EDIT: As someone pointed out in the comment, this may actually depends on the implementation as it requires explicitly that the set is not modified, but states no explicit requirement on the argument and whether it's been moved or not.
Upvotes: 2
Reputation: 153935
A std::move()
ed object passed to a standard library function should be considered to be moved from: the library is free to consider the object to be its only reference, i.e., it may move from it even if it doesn't use it. The relevant clause is 17.6.4.9 [res.on.arguments] paragraph 2, third bullet (it seems identical in C++11 and C++14):
If a function argument binds to an rvalue reference, the implementation may assume that this parameter is a unique reference to this argument. ...
Upvotes: 7
Reputation: 42564
The third bullet of [res.on.arguments]/1 from N3936:
If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument. [ Note: If the parameter is a generic parameter of the form
T&&
and an lvalue of typeA
is bound, the argument binds to an lvalue reference (14.8.2.1) and thus is not covered by the previous sentence. —end note ] [ Note: If a program casts an lvalue to an xvalue while passing that lvalue to a library function (e.g. by calling the function with the argumentmove(x)
), the program is effectively asking that function to treat that lvalue as a temporary. The implementation is free to optimize away aliasing checks which might be needed if the argument was an lvalue. —end note ]
despite on its face being about aliasing, can be interpreted as allowing the implementation to do virtually anything to an argument that is passed to a standard library function bound to an rvalue reference. As Fabio says, there are situations in which tightening this specification could be useful, and the committee is looking at some of them.
Upvotes: 3
Reputation: 3890
This is (very simmilar to) LWG Active issue 2362 which deals with emplace. IIRC the sentiment is that it should be guaranteed that the object is only moved iff it is inserted/emplaced. With emplace it seems to be not trivial to achieve. I do not remember if the situation is easier for insert.
Upvotes: 3