C++11标准在与标准库相关的自身移动赋值方面有什么规定?更具体地说,如果有的话,对于selfAssign
做了什么是有保证的吗?
template<class T>
std::vector<T> selfAssign(std::vector<T> v) {
v = std::move(v);
return v;
}
C++11标准在与标准库相关的自身移动赋值方面有什么规定?更具体地说,如果有的话,对于selfAssign
做了什么是有保证的吗?
template<class T>
std::vector<T> selfAssign(std::vector<T> v) {
v = std::move(v);
return v;
}
17.6.4.9 函数参数 [res.on.arguments]
1 除非另有明确规定,否则以下规定适用于 C++ 标准库中定义的所有函数参数。
...
- 如果函数参数绑定到一个右值引用参数,则实现可以假设该参数是对此参数的唯一引用。[注意:如果参数是形如 T&& 的通用参数,并且绑定了类型为 A 的左值,则该参数绑定到一个左值引用(14.8.2.1),因此不受前面一句话的限制。—注解] [注意:如果程序将左值转换为 xvalue 并在将该左值传递给库函数时(例如通过使用 move(x) 调用函数),程序实际上要求该函数将该左值视为临时变量。实现可以优化掉可能需要的别名检查,如果该参数是一个左值的话。—注解]
因此,实现std::vector<T, A>::operator=(vector&& other)
被允许假设other
是一个prvalue。如果other
是一个prvalue,则不可能进行自我移动赋值。
可能发生的情况是:
v
将处于无资源状态(容量为0)。如果v
已经具有0容量,则这将是一个无操作。
更新
最新工作草案,N4618已经修改以明确说明在MoveAssignable
要求中的表达式:
t = rv
(其中rv
是一个右值),如果t
和rv
没有引用同一对象,则t
只需要是赋值之前rv
的等效值。无论如何,rv
在赋值后的状态都是未指定的。这里有一个额外的注释以进一步澄清:
rv
仍然必须符合使用它的库组件的要求,无论t
和rv
是否引用同一对象。
selfAssign
由于未满足移动赋值运算符的前置条件而会调用未定义的行为。我的理解是,在调用std::swap(v, v)
时,std::swap
将对自我移动赋值。这是否意味着调用std::swap(v, v)
是未定义的行为? - Bjarke H. Roune&&
对于参数来说暗示了__restrict
; 我想知道是否有任何编译器已经利用了这一点。 - Matthieu M.&&
参数的一般性声明。在您编写的代码中,您不会受到此限制。 - Nicol BolasT
为 MoveAssignable
。即使 T
处于已移动状态,该要求仍然成立。 - Howard Hinnant有Eric Niebler的相关帖子,其中包含多个链接,例如Howard Hinnant的这个答案。
最新的C++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
留在某个有效状态。
T
的自我移动分配。 - Xeo