含noexcept移动构造的对象,std::vector未调用其移动构造函数
解决移动构造与复制构造的使用困扰
咱们先把你的代码补全并直击核心问题——因为std::unique_ptr是独占所有权的智能指针,你的OWUP类禁用复制构造是完全正确的,但必须显式提供移动构造和移动赋值运算符,否则容器(比如std::vector)在调整内存、插入元素时会尝试调用复制构造,直接触发编译失败。
第一步:完善OWUP类的移动语义
这是解决问题的基础,必须给OWUP补上移动相关的函数:
#include <memory> #include <vector> class OWUP { public: OWUP() : data(nullptr) {} // 明确禁用复制构造和复制赋值 OWUP(const OWUP&) = delete; OWUP& operator=(const OWUP&) = delete; // 显式提供移动构造(加noexcept很关键) OWUP(OWUP&& other) noexcept : data(std::move(other.data)) { other.data = nullptr; // 确保原对象处于有效但无意义的安全状态 } // 显式提供移动赋值 OWUP& operator=(OWUP&& other) noexcept { if (this != &other) { data = std::move(other.data); other.data = nullptr; } return *this; } // 方便测试的构造函数 explicit OWUP(int val) : data(std::make_unique<int>(val)) {} private: std::unique_ptr<int> data; };
这里的noexcept标记不能少:容器在执行emplace_back这类操作时,如果移动构造是noexcept的,会优先使用移动而非拷贝,还能避免不必要的内存分配回滚。
第二步:确保One和Two类的容器操作使用移动语义
你的One和Two类不需要额外定义构造/赋值函数,只要保证往容器里加元素时用移动而非复制逻辑:
class One { public: // 直接在容器内存中构造OWUP,避免临时对象开销 void add_owup(int val) { owups.emplace_back(val); } // 转移OWUP的所有权到容器 void move_owup(OWUP&& owup) { owups.push_back(std::move(owup)); } private: std::vector<OWUP> owups; }; class Two { public: // 转移One的所有权到容器 void add_one(One&& one) { ones.push_back(std::move(one)); } // 直接在容器内存中构造空One对象 void emplace_one() { ones.emplace_back(); } private: std::vector<One> ones; };
- 用
emplace_back直接在容器内存里构造对象,跳过临时对象的创建 - 用
std::move把对象的所有权转移给容器,触发移动构造而非复制
常见坑点排查
- 忘记提供移动构造/赋值:如果
OWUP只有删除的复制构造,没有移动构造,容器操作会直接编译报错——vector没法复制独占所有权的对象 - 移动构造没加
noexcept:某些场景下vector会 fallback 到复制构造(如果移动构造可能抛出异常),导致编译失败 - 误用拷贝而非移动:比如直接
push_back(owup)而不是push_back(std::move(owup)),会触发复制构造的编译错误
测试示例
int main() { One o1; o1.add_owup(10); o1.move_owup(OWUP(20)); Two t; t.add_one(std::move(o1)); // 把o1的所有权转移给t的容器 t.emplace_one(); // 直接构造空的One对象 return 0; }
这段代码可以正常编译运行,所有操作都是基于移动语义,完全没有复制行为。
内容的提问来源于stack exchange,提问作者73nismit
相关产品推荐
相关产品推荐

