Что происходит с подвижным объектом, когда его вставка в std:: set терпит неудачу?

Что произойдет, если движимый объект, если я позвоню std::set<>::insert, и вставка не выполняется потому что уже есть объект с тем же ключом, присутствующим в набор. В частности, справедливо следующее:

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))
    // ...
    {
    }
};

и

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);
}

После registry.insert, когда вставка отсутствует, имеет o было перемещено или нет. (Если бы это могло быть перемещено, мне нужно сохраните копию строки перед рукой, чтобы использовать ее в сообщение об ошибке. (И да, я знаю, что я всегда могу написать:

throw std::runtime_error( "Duplicate entry for " + status->first.key );

Это то, что я, вероятно, сделаю. Но я все равно хотел бы знать что стандарт говорит об этом.)

Ответ 1

A std::move() ed объект, переданный в стандартную библиотечную функцию, должен считаться перенесенным из: библиотека может считать объект своей единственной ссылкой, т.е. он может перейти от него, даже если он не используй это. Соответствующим пунктом является 17.6.4.9 [res.on.arguments] параграф 2, третий пул (он кажется идентичным в С++ 11 и С++ 14):

Если аргумент функции связывается с ссылкой на rvalue, реализация может предположить, что этот параметр является уникальной ссылкой на этот аргумент....

Ответ 2

Хорошо, чтобы ответить на ваш последний вопрос

Мне все равно хотелось бы знать, что говорится в этом стандарте

стандарт указывает, что произойдет с insert(t) в Table 102 - Associative container requirements, p717 из N3376 (выделение мое):

Требуется: если t является выражением non-const rvalue, value_type должен быть MoveInsertable в X; в противном случае value_type должен быть CopyInsertable в X.

Эффекты: Вставляет t тогда и только тогда, когда в контейнере нет элемента с ключом, эквивалентным ключу t. Компонент bool возвращенной пары является истинным тогда и только тогда, когда происходит вставка, и компонент итератора пары указывает на элемент с ключом, эквивалентным ключу t.

поэтому я бы сказал, что ничего не должно произойти и что ваш Object по-прежнему действителен и не является неопределенным.

EDIT. Как заметил кто-то в комментарии, это может фактически зависеть от реализации, поскольку она явно требует, чтобы набор не был изменен, но не указывает на явное требование к аргументу и было ли оно перемещен или нет.

Ответ 3

Это (очень похоже на) LWG Активная проблема 2362, которая касается emplace. IIRC считает, что следует гарантировать, что объект перемещается только в том случае, если он вставлен/установлен. С emplace кажется, что это не так просто. Я не помню, легче ли вставить ситуацию.

Ответ 4

Третья пуля [res.on.arguments]/1 из N3936:

Если аргумент функции связывается с параметром ссылки rvalue, реализация может предполагать, что этот параметр является уникальной ссылкой на этот аргумент. [Примечание: если параметр является общим параметром формы T&& и привязано значение l A, этот аргумент привязывается к ссылке lvalue (14.8.2.1) и, таким образом, не покрывается предыдущим предложением. -end note] [Примечание. Если программа передает значение lvalue в значение x, передавая это lvalue библиотечной функции (например, вызывая функцию с аргументом move(x)), программа эффективно запрашивает эту функцию для обработки этого lvalue как временный. Реализация бесплатна для оптимизации проверок псевдонимов, которые могут потребоваться, если аргумент был lvalue. -end note]

несмотря на то, что его лицо связано с псевдонимом, его можно интерпретировать как позволяющее реализации делать практически что угодно до аргумента, который передается стандартной библиотечной функции, связанной с ссылкой rvalue. Как Фабио говорит, бывают ситуации, когда ужесточение этой спецификации может быть полезно, и комитет смотрит на некоторые из них.