【问题标题】:What does the standard library guarantee about self move assignment?标准库对自移动分配有什么保证?
【发布时间】:2012-10-19 02:40:28
【问题描述】:

C++11 标准对与标准库相关的自移动赋值有什么看法?更具体地说,selfAssign 所做的事情有什么保证(如果有的话)?

template<class T>
std::vector<T> selfAssign(std::vector<T> v) {
  v = std::move(v);
  return v;
}

【问题讨论】:

  • @Mark 我不认为这是重复的。这个问题是关于写你自己的。这个问题是关于标准库保证什么的。
  • 请注意,这涉及T的自移动分配。
  • @Xeo 我删除了那行。感谢您指出错误。
  • 投票重新打开标记为“重复”不包括对标准容器移动分配行为的保证,并且没有一个答案提供标准参考,如 Howard Hinnant 对此线程的回答

标签: c++ stl c++11 move-semantics


【解决方案1】:

17.6.4.9 函数参数 [res.on.arguments]

1 以下每一项都适用于定义的函数的所有参数 在 C++ 标准库中,除非另有明确说明。

...

  • 如果函数参数绑定到右值引用参数,则实现可能假定此参数是对 这个论点。 [注:如果参数是泛型参数 形成 T&& 并且绑定了 A 类型的左值,则参数绑定到 左值引用(14.8.2.1),因此不包括在前面 句子。 — end note ] [ 注意:如果程序将左值转换为 xvalue 同时将该左值传递给库函数(例如,通过 调用带有参数 move(x)) 的函数,程序是 有效地要求该函数将该左值视为临时值。 该实现可以免费优化别名检查 如果参数是左值,则可能需要。 ——尾注]

所以,std::vector&lt;T, A&gt;::operator=(vector&amp;&amp; other) 的实现可以假设other 是prvalue。如果other 是prvalue,则无法进行自移动分配。

可能发生的事情:

v 将处于无资源状态(0 容量)。如果v 已经有 0 个容量,那么这将是一个空操作。

更新

latest working draft, N4618 已被修改,以明确说明在MoveAssignable 中要求表达式:

t = rv

(其中rv 是一个右值),如果trv 不引用同一个对象,t 只需在赋值之前是rv 的等效值。无论如何,rv 的状态在分配后是未指定的。有一个附加说明需要进一步澄清:

rv 必须仍然满足使用它的库组件的要求,无论 trv 是否引用同一个对象。

【讨论】:

  • 如果我正确理解了您的报价,函数 selfAssign 然后会调用未定义的行为,因为未满足移动赋值运算符的先决条件。我的理解是std::swap 将在调用std::swap(v, v) 时进行自我移动分配。这是否会使调用 std::swap(v, v) 成为未定义的行为?
  • 有趣。这意味着 &amp;&amp; 暗示 __restrict 用于参数然后;我想知道是否有任何编译器利用了这一点。
  • @MatthieuM.:这只是标准对 它自己的 功能的描述;这不是关于&amp;&amp; 参数的一般性陈述。在您编写的代码中,您不会受到限制。
  • @BjarkeH.Roune:swap(v, v) 是合法的并且需要工作。它通常会这样做,因为自移动分配是使用已移动值完成的(假设我们不是在谈论具有专用交换的向量,该交换也需要与自交换一起使用)。在通用自交换中,您将分配从未指定的值转移到未指定的值。因此,只要它不崩溃,发生什么并不重要。 swap(t, t) 要求 TMoveAssignable。即使 T 处于移出状态,该要求仍然有效。
  • @HowardHinnant 我不确定我是否理解你的推理。我做了主题a question
【解决方案2】:

a relevant post by Eric Niebler 有多个链接,例如到this answer by Howard Hinnant

最新的С++20工作草案(N4861)在我看来仍然有点模棱两可。但是,最近有一个Library Working Group issue 2839[lib.types.movedfrom]/2 处添加了以下显式声明:

在 C++ 标准库中定义的类型的对象可以移动分配 (11.4.6 [class.copy.assign]) 给它自己。除非另有说明,否则此类分配会将对象置于有效但未指定的状态。

它已经在 C++23 的 N4885 工作草案中。

因此,selfAssign 保证不会导致未定义的行为,并且由于 std::vector 没有额外的保证,因此将 v 保持在某个有效状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-28
    • 2018-08-24
    • 2022-12-05
    • 2011-05-03
    • 2013-12-03
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多