如何修复包含持有std::unique_ptr的对象的std::vector问题
修复包含
std::unique_ptr的类vector代码问题 咱们来一步步拆解你代码里的核心问题,逐个修复:
1. Nested的拷贝构造函数完全非法
std::unique_ptr的核心设计就是独占对象所有权,它没有拷贝构造函数(被显式删除了),只能通过移动语义转移所有权。你写的拷贝构造函数:
Nested(const Nested& t) { node = std::move(t.node); };
这里有两个致命问题:
t是const Nested&,意味着t.node是const std::unique_ptr<Container>&,std::move无法作用于const对象——毕竟移动操作会修改原对象的指针(把它置空),而const对象不允许被修改。- 就算去掉const,直接尝试拷贝
unique_ptr本身也是编译器不允许的,这违背了它的独占语义。
修复方案:
把Nested设计成可移动但不可拷贝的类型,这完全契合unique_ptr的特性:
struct Nested{ std::unique_ptr<Container> node; // 构造函数:接收unique_ptr并转移所有权 Nested(std::unique_ptr<Container> t) : node(std::move(t)) {} // 显式删除拷贝构造和拷贝赋值,禁止编译器默认生成 Nested(const Nested&) = delete; Nested& operator=(const Nested&) = delete; // 让编译器自动生成移动构造和移动赋值(完全够用) Nested(Nested&&) = default; Nested& operator=(Nested&&) = default; };
2. std::vector的兼容性问题
你可能担心:vector要求元素可拷贝?其实C++11及以后,vector完全支持仅可移动的元素——只要你使用移动语义的操作(比如emplace_back、push_back(std::move(obj))),容器就能正常工作。
3. 补全并修复main函数的截断代码
你main里的代码Nested(UC...明显是输入截断了,我给你补全成合理的示例,顺便用更安全的std::make_unique(C++14引入)代替直接new:
int main() { // 创建一个Container,它的edges包含两个Nested元素 auto object = std::make_unique<Container>( std::initializer_list<Nested>{ Nested(std::make_unique<Container>()), Nested(std::make_unique<Container>()) } ); // 后续还可以用emplace_back直接在容器内构造Nested,更高效 object->edges.emplace_back(std::make_unique<Container>()); return 0; }
完整可运行的修复后代码
#include <vector> #include <memory> struct Container { struct Nested{ std::unique_ptr<Container> node; Nested(std::unique_ptr<Container> t) : node(std::move(t)) {} // 禁止拷贝 Nested(const Nested&) = delete; Nested& operator=(const Nested&) = delete; // 默认支持移动 Nested(Nested&&) = default; Nested& operator=(Nested&&) = default; }; std::vector<Nested> edges; }; using UCont = std::unique_ptr<Container>; // 用using比typedef更现代 using Nested = Container::Nested; int main() { auto object = std::make_unique<Container>( std::initializer_list<Nested>{ Nested(std::make_unique<Container>()), Nested(std::make_unique<Container>()) } ); object->edges.emplace_back(std::make_unique<Container>()); return 0; }
额外小建议
- 尽量用
using代替typedef,语法更灵活,可读性更好。 - 永远优先用
std::make_unique/std::make_shared代替直接new,它们能避免内存泄漏风险,代码也更简洁。
内容的提问来源于stack exchange,提问作者saha
相关产品推荐
相关产品推荐

