std::remove, std::move(range) and moved-from elements



查看标准::删除引用我看到:

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

删除是通过移动(通过移动分配)范围内的元素来完成的。指向范围的新逻辑端和物理端之间的元素的迭代器仍然是可取消引用的,但元素本身具有未指定的值(根据 MoveAssignable 后置条件)。

所以,我看到可移动可分配的锥体:

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

到目前为止,还可以。 关于可移动可分配概念的问题:

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

我可以通过读取其值或重新分配其值来重用"movefrom"变量吗?

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

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

将区域中的元素 [第一个、最后一个) 移动到从 d_first 开始的另一个区域。执行此操作后,移出区域中的元素仍将包含相应类型的有效值,但不一定与移动前的值相同。

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

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

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

std::move([alg.move])的描述只是说元素被移动,并且没有对移出的对象进行注释。std::remove([alg.remove])的描述有一个非规范性的注释:

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

因此,cpp首选项恰好在这两个页面上使用了不同的措辞,但它们的含义完全相同。

现在,鉴于std::string s1已被移出,这样做是否有效

std::cout << s1;

是的,这是允许的,因为s1是"有效的",但它没有用,因为您无法保证将输出的内容。 另一方面

s1 = "cde";

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

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

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

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

由于u.release()u为空/空,因此我们实际上可以保证移自对象为空/空。 对于移动构造函数和采用不同模板参数unique_ptr的模板化构造函数和赋值,也提供了类似的保证,因此移自unique_ptr始终为空/空。

最新更新