使用移动元素调整向量大小是否正确?
Is it correct to resize a vector with moved-elements?
我正在尝试理解移动语义的一般规则。
特别是容器和包含的元素。
原因是我试图在所有权和迭代器失效的上下文中理解移动。
为此,我正在处理一些复杂性不断增加的案例,涉及典型容器、一般包含类型 T
、一般 g
和 f
函数。
(也许一个重要的额外细节是 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
,但不知道它的内容(新元素是默认构造的,但它们是什么?)。
我正在尝试理解移动语义的一般规则。 特别是容器和包含的元素。
原因是我试图在所有权和迭代器失效的上下文中理解移动。
为此,我正在处理一些复杂性不断增加的案例,涉及典型容器、一般包含类型 T
、一般 g
和 f
函数。
(也许一个重要的额外细节是 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
,但不知道它的内容(新元素是默认构造的,但它们是什么?)。