Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens to a movable object when its insertion in an std::set fails?

Tags:

c++

c++11

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.)

like image 248
James Kanze Avatar asked Sep 12 '14 13:09

James Kanze


3 Answers

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. ...

like image 176
Dietmar Kühl Avatar answered Oct 30 '22 12:10

Dietmar Kühl


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.

like image 2
Fabio Fracassi Avatar answered Oct 30 '22 11:10

Fabio Fracassi


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 type A 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 argument move(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.

like image 2
Casey Avatar answered Oct 30 '22 11:10

Casey