vector<unique_ptr<T>>调用resize时的行为及相关移动语义疑问
你的推测是对的,存储std::unique_ptr的std::vector扩容时确实会移动元素而非拷贝,因为std::unique_ptr的拷贝构造函数被删除,不支持拷贝操作。下面是你两个疑问的解答:
问题1:是否存在类似浅拷贝/深拷贝的浅移动/深移动相关概念?
C++语言标准没有对「浅移动」「深移动」做官方定义,但业界讨论中经常会用这两个概念和深浅拷贝做对应:
- 浅移动:仅转移资源的所有权,不复制资源本身。这是绝大多数标准库类型移动构造的默认行为,比如
std::unique_ptr的移动就是典型的浅移动:移动后新的std::unique_ptr持有原指针指向的堆内存,原std::unique_ptr被置空,全程没有复制堆上的实际数据,开销极低。 - 深移动:移动构造时会复制底层资源的内容,而非仅转移所有权。这种场景非常少见,一般只有自定义移动构造函数时才可能实现出这种行为,从效果上看和深拷贝几乎没有区别,也不会带来移动的性能收益,因此日常开发几乎不会用到。
问题2:vector扩容时选择拷贝还是移动的行为,是由vector类定义决定,还是由存入的元素类的拷贝、移动构造函数重载实现决定?
这个选择的判断逻辑是std::vector的C++标准定义规定的,但判断的核心依据是元素类型的特性:std::vector扩容时默认优先选择调用元素的移动构造函数,前提是元素的移动构造函数被标记为noexcept——如果移动构造没有声明noexcept,扩容过程中如果移动抛出异常,会导致已经移动的元素被破坏、无法恢复原有状态,违反std::vector的强异常安全保证,所以这种情况下vector会退而选择调用拷贝构造函数。
如果元素类型像std::unique_ptr一样,拷贝构造函数被删除、仅存在可用的移动构造函数,那vector不管移动构造有没有标记noexcept,都只能调用移动构造,因为拷贝操作本身已经不可用。
内容的提问来源于stack exchange,提问作者Guanwei HU
相关产品推荐
相关产品推荐

