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),因此上一句未涵盖。— end note ] [ 注意:如果程序将左值转换为 xvalue,同时将该左值传递给库函数(例如,通过使用参数 move(x) 调用函数),则程序实际上是在要求该函数处理该左值作为临时。如果参数是左值,则该实现可以免费优化别名检查,这可能需要。——尾注]
因此,std::vector<T, A>::operator=(vector&& other)
允许的实现假定它other
是一个prvalue。如果other
是纯右值,则无法进行自移动分配。
可能发生的情况:
v
将处于无资源状态(0 容量)。如果v
已经有 0 容量,那么这将是一个空操作。
更新
最新的工作草案 N4618已被修改为在要求中明确说明MoveAssignable
:
t = rv
(其中rv
是一个右值),如果并且不引用同一个对象,则只需是赋值之前t
的等效值。无论如何,分配后的状态是未指定的。有一个附加说明需要进一步说明:rv
t
rv
rv
rv
必须仍然满足使用它的库组件的要求,无论是否引用同一个对象t
。rv
Eric Niebler有一个相关的帖子,其中包含多个链接,例如Howard Hinnant 的这个答案。
最新的С++20工作草案(N4861)在我看来仍然有点模棱两可。但是,最近有一个图书馆工作组问题 2839,它在以下位置添加了以下明确声明[lib.types.movedfrom]/2
:
C++ 标准库中定义的类型的对象可以移动分配(11.4.6 [class.copy.assign])给它自己。除非另有说明,否则此类分配会将对象置于有效但未指定的状态。
它已经在 C++23 的 N4885 工作草案中。
因此,selfAssign
保证不会导致未定义的行为,并且由于没有额外的保证std::vector
,因此保持v
在某些有效状态。