对元素已被移动的std::vector执行resize操作是否合法?
C++标准对移动语义的基础约定是:被移动的对象处于「有效但未指定状态」,所有无前置条件的操作都可以合法调用,这是判断所有场景合法性的基础。
场景0
完全合法。移动后的vector执行赋值操作是标准明确允许的行为,赋值会直接覆盖原有未指定的状态,不存在任何风险。
std::vector<T> v(100, t); f(std::move(v)); v = make_a_vector();
场景1
确实属于不合法代码。g接收vector的const左值引用,内部通常会执行读取vector大小、访问元素等有前置条件的操作,而移动后的vector状态未指定,无法满足这些操作的前置要求,会触发未定义行为。
std::vector<T> v(100, t); f(std::move(v)); g(v);
场景2
合法。std::vector::resize 是无前置调用要求的成员函数,无论移动后的vector当前处于哪种有效状态,resize都可以正常执行:如果移动后vector为空,resize会直接分配新空间;如果移动后vector仍持有元素,resize会按需销毁多余元素或新增元素,全程由vector自身管理生命周期,没有安全问题。
std::vector<T> v(100, t); f(std::move(v)); v.resize(120);
场景3(核心疑问)
只要你的类型T符合C++标准对容器元素的常规要求,这段代码完全合法,不会触发未定义行为,理由如下:
std::make_move_iterator只是把普通迭代器包装成返回右值引用的迭代器,h遍历范围时如果对元素执行移动构造/赋值操作,只会让原vector内的元素进入「有效但未指定」状态,这本身是符合标准约定的。vector::resize对原有元素的操作只有两类:要么是销毁元素(缩容场景),要么是移动/拷贝元素到新分配的内存(扩容场景)。而C++标准要求所有可放入容器的类型,都必须支持对被移动对象执行销毁、移动赋值操作,这些操作都是无前置条件的合法操作。- 唯一的例外是自定义类型
T本身违反标准约定,被移动后执行销毁/移动操作会触发异常或错误,这属于类型实现的bug,和vector的resize操作无关。
std::vector<T> v(100); h(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())); v.resize(120);
相关函数签名
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);
内容的提问来源于stack exchange,提问作者alfC
相关产品推荐
相关产品推荐

