使用移动元素调整向量大小是否正确?

Is it correct to resize a vector with moved-elements?

我正在尝试理解移动语义的一般规则。 特别是容器和包含的元素。

原因是我试图在所有权和迭代器失效的上下文中理解移动。 为此,我正在处理一些复杂性不断增加的案例,涉及典型容器、一般包含类型 T、一般 gf 函数。 (也许一个重要的额外细节是 f 可能会或可能不会实际执行移动操作,或者它可能在运行时视情况而定。)

思路是引入案例3,这是本题的核心

案例 0

首先是一个比较没有争议的案例,这个可以:

std::vector<T> v(100, t);
f(std::move(v));
v = make_a_vector();

案例一

然而,use-after-move 可能是臭代码

std::vector<T> v(100, t);
f(std::move(v));
g(v);

我想大多数人都同意上面的这个是不对的。 规则是(据我所知)移动后的唯一操作应该是赋值。 我认为这尤其是因为它是未记录的(未定义但有效的状态)什么是移动向量的状态,(或者即使它被移动了。)。 因此,充其量 v 是空的,最坏的情况下 v 是未指定的状态,因此 g 可以在此范围内执行未指定的操作。

案例二:

std::vector<T> v(100, t);
f(std::move(v));
v.resize(120);

是否正确? 它不是赋值,但 resize 没有先决条件。 (找到这个

案例 3:

现在是真正棘手的案例。

std::vector<T> v(100);
h(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
v.resize(120);

(这里,h 是一个带迭代器的函数,假设它隐含地引用 range [iterator1, iterator2)。)

这是正确的代码吗? 原因是 .resize 似乎要播放、移动、交换和复制 T.

类型的移出对象

总而言之,调整其元素已被(可能)移动的向量的大小是否正确?


编辑: 为了论证,让我们指定函数的签名,以防它们与答案相关:

template<class T> void f(std::vector<T>&&); 
template<class T> void g(std::vector<T> const&);
template<class It> void h(It first, It last);

如果它是标准库对象的向量,则保证调整向量大小是安全的。参见 What constitutes a valid state for a "moved from" object in C++11?

如果是您自己的对象的向量——那么问题又回到了您是否将自己的对象设计为在移动后有效。

std::vector<T> v(100, t);
f(std::move(v));
v.resize(120);

与您的案例 1 相似

std::vector<T> v(100, t);
f(std::move(v));
g(v);

vector::resize 没有先决条件,但您不知道以前的状态。 它可能是空的,有一些大小(具有未指定的值)。

所以在v.resize(120)之后,你只知道新的尺寸是120,但不知道它的内容(新元素是默认构造的,但它们是什么?)。