首页 文章

std :: remove,std :: move(range)和move-from元素

提问于
浏览
2

看看std :: remove参考我看到:

template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );

通过移动(通过移动分配)范围中的元素来完成移除 . 指向新逻辑结束和范围物理结束之间的元素的迭代器仍然是可解除引用的(根据MoveAssignable后置条件) .

所以,我看到MoveAssignable conept:

t = rv   // Post-condition:The new value of rv is unspecified.

到目前为止,没关系 . 关于MoveAssignable概念的问题:

std::string s1 = "abc";
std::string s2;
s2 = std::move(s1);
std::cout << s1;    // is this code valid?
s1 = "cde";         // is this code valid?

我可以通过读取其值或重新赋值来重用“移动自”变量吗?

现在我正在查看std :: move参考,它看起来有点令人惊讶:

template< class InputIt, class OutputIt >
OutputIt move( InputIt first, InputIt last, OutputIt d_first );

将[first,last]范围内的元素移动到从d_first开始的另一个范围 . After this operation the elements in the moved-from range will still contain valid values of the appropriate type ,但不一定与移动前的值相同 .

因此,move-from元素在std :: remove和std :: move中以不同的方式定义,尽管它们应该是相同的 . 哪一个是正确的?重新使用(或不使用)移动元素的规则是什么?

1 回答

  • 1

    标准中的实际措辞可在[lib.types.movedfrom]部分找到:

    可以从([class.copy])移动C标准库中定义的类型的对象 . 可以显式指定或隐式生成移动操作 . 除非另有规定,否则此类移动物体应处于有效但未指定的状态 .

    std::move ([alg.move])的描述简单地说,元素被移动并且不对移动的对象做出任何评论 . std::remove ([alg.remove])的描述有一个非规范性的说明:

    注意:范围[ret,last]中的每个元素,其中ret是返回值,具有有效但未指定的状态,因为算法可以通过从最初在该范围内的元素移动来消除元素 .

    因此,cppreference恰好在这两个页面上使用不同的措辞,但它们的含义完全相同 .

    现在,鉴于 std::string s1 已被移除,是否有效

    std::cout << s1;
    

    是的,这是允许的,因为 s1 是"valid",但它没用,因为你无法保证输出的内容 . 另一方面,

    s1 = "cde";
    

    既安全又有用,因为 s1 的任何先前内容都被丢弃了 .

    有关"unless otherwise specified"的示例,请查看 std::unique_ptr<T> ([unique.ptr.single.asgn])的移动赋值运算符:

    unique_ptr& operator=(unique_ptr&& u) noexcept;
    

    效果:将所有权从u转移到*,就像调用reset(u.release()),然后调用get_deleter()= std :: forward <D>(u.get_deleter())一样 .

    由于 u.release() 离开 u empty / null,我们实际上保证move-from对象将为空/ null . 类似的保证是针对移动构造函数和模板化构造函数以及使用不同模板参数的 unique_ptr 赋值,因此移动的 unique_ptr 始终为空/空 .

相关问题