当一个可移动对象插入std :: set失败时会发生什么?

时间:2014-09-12 13:48:45

标签: c++ c++11

如果我打电话给可移动物体会发生什么 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 );

我可能会这样做。但我还是想知道 标准对此有何看法。)

4 个答案:

答案 0 :(得分:6)

传递给标准库函数的std::move() ed对象应该被认为是从以下位置移动的:库可以自由地将该对象视为它唯一的引用,即它可以从它移动,即使它没有& #39;使用它。相关条款是17.6.4.9 [res.on.arguments]第2段,第3个子弹(在C ++ 11和C ++ 14中似乎相同):

  

如果函数参数绑定到右值引用,则实现可以假定此参数是对此参数的唯一引用。 ...

答案 1 :(得分:2)

好的,回答你的上一个问题

  

我仍然想知道标准对此有何看法

该标准规定了insert(t)中的Table 102 - Associative container requirements,N3376的第717页(强调我的)所发生的事情:

  

要求:如果t是非const rvalue表达式,则value_type应为MoveInsertable为X;否则,value_type应为CopyInsertable到X.

     

效果:当且仅当容器中没有元素且密钥等于t 的键时插入t 。当且仅当插入发生时,返回对的bool组件才为真,并且该对的迭代器组件指向具有等效于t键的键的元素。

所以我会说没有任何事情会发生,并且您的Object仍然有效且未指定状态。

编辑:正如有人在评论中指出的那样,这可能实际上取决于实现,因为它明确要求不修改集合,但声明对参数没有明确的要求以及是否已经移动与否。

答案 2 :(得分:2)

这是(非常类似于)LWG Active问题2362,它涉及到安慰。 IIRC的观点是,应该保证只有在插入/放置对象时才移动对象。通过安抚,实现它似乎并非无足轻重。我不记得插入情况是否更容易。

答案 3 :(得分:2)

来自N3936的[res.on.arguments] / 1的第三个子弹:

  

如果函数参数绑定到右值引用参数,则实现可以假设   此参数是对此参数的唯一引用。 [注意:如果参数是T&&形式的泛型参数且绑定了A类型的左值,则参数绑定到左值引用(14.8.2.1)因此不在前一句中。 -end note ] [注意:如果程序在将左值传递给库函数时将左值转换为x值(例如通过使用参数{{1调用函数) }},程序有效地要求该函数将该左值作为临时值处理。实现可以自由地优化别名检查,如果参数是左值,则可能需要这些检查。 -end note ]

尽管表面上存在别名,但可以解释为允许实现对传递给绑定到右值引用的标准库函数的参数执行几乎任何操作。正如Fabio says所述,在某些情况下,收紧此规范可能会有用,委员会正在研究其中的一些。