使用std::map与unique_ptr时触发隐式删除拷贝构造函数的解决方法
解决包含std::unique_ptr的类存入std::map后的拷贝构造错误
问题根源
std::unique_ptr是独占所有权的智能指针,它的拷贝构造函数被显式删除。当你的Cb类包含std::unique_ptr成员时,编译器会自动删除Cb的拷贝构造函数和拷贝赋值运算符。因此任何需要拷贝Cb对象的操作(比如直接赋值、按值取出map元素)都会触发“调用隐式删除的拷贝构造函数”错误。
用std::move插入成功,是因为move操作转移了Cb对象的所有权(包括内部的unique_ptr),并没有触发拷贝。但取出时如果尝试按值获取对象,本质还是在做拷贝,所以错误重现。
解决方案
1. 使用引用/指针访问map中的对象(推荐,无所有权转移)
直接获取map元素的引用,避免拷贝对象,这样可以安全访问map中存储的Cb实例,且不会破坏map内的对象:
#include <iostream> #include <map> #include <memory> class Cb { public: std::unique_ptr<int> ptr; Cb(int val) : ptr(std::make_unique<int>(val)) {} // 若使用map的operator[],需确保Cb有默认构造函数 Cb() = default; }; int main() { std::map<int, Cb> cb_map; Cb cb(10); cb_map[1] = std::move(cb); // 方式1:通过operator[]获取引用(key不存在时会默认构造Cb) auto& cb_ref = cb_map[1]; std::cout << *cb_ref.ptr << std::endl; // 正常输出10 // 方式2:用find查找(更安全,避免不必要的默认构造) auto it = cb_map.find(1); if (it != cb_map.end()) { auto& cb_ref = it->second; std::cout << *cb_ref.ptr << std::endl; } return 0; }
2. 用std::move转移map中对象的所有权
如果确实需要把Cb对象从map中取出并完全接管其所有权,可以用std::move转移,此时map中原位置的Cb对象会变为空(内部unique_ptr被置为nullptr):
auto cb_moved = std::move(cb_map[1]); std::cout << *cb_moved.ptr << std::endl; // 正常输出10 // 此时cb_map[1].ptr已为空,直接访问会触发未定义行为
3. 改用std::shared_ptr共享所有权(适合多持有者场景)
如果业务需要多个地方同时持有Cb对象的所有权,可以把std::unique_ptr替换为std::shared_ptr。shared_ptr支持拷贝(通过引用计数共享所有权),此时Cb类的拷贝构造函数会被正常生成,插入和取出都可以直接使用拷贝操作:
class Cb { public: std::shared_ptr<int> ptr; Cb(int val) : ptr(std::make_shared<int>(val)) {} }; int main() { std::map<int, Cb> cb_map; Cb cb(10); cb_map[1] = cb; // 直接拷贝,无错误 auto cb_copy = cb_map[1]; // 拷贝对象,shared_ptr引用计数增加 std::cout << *cb_copy.ptr << std::endl; // 输出10 std::cout << *cb_map[1].ptr << std::endl; // 同样输出10 return 0; }
方案选择建议
- 仅需访问map中的对象:优先用引用/指针方案,无额外开销且安全。
- 需要将对象从map中移除并接管所有权:用std::move方案。
- 需要多组件共享对象所有权:改用std::shared_ptr方案。
内容的提问来源于stack exchange,提问作者Nick X Tsui
相关产品推荐
相关产品推荐

