传入原始指针构造unique_ptr时的地址一致问题及相关疑问
示例代码
#include <iostream> #include <memory> class foo{ int x; public: foo(): x(0) {} foo(int a): x(a) {} foo(const foo& f): x(f.x) {} }; int main(){ foo *ptr = new foo(5); std::unique_ptr<foo> uptr(ptr); std::cout << ptr << "\n"; std::cout << uptr.get() << "\n"; return 0; }
输出结果
0x5c7bc80 0x5c7bc80
疑问解答
是否是将原始指针传入了拷贝构造函数?unique_ptr的拷贝构造函数不是被删除(=delete)了吗?为何原始指针与unique_ptr的地址相同?
这不是调用拷贝构造函数,unique_ptr的拷贝构造确实已被删除。你这里调用的是unique_ptr的转换构造函数(接受原始指针的重载版本)。地址相同是因为unique_ptr本质是封装了原始指针的容器,get()方法就是返回它内部保存的原始指针值,所以两者指向的内存地址自然一致。需要注意:此时原始指针的所有权已经转移给unique_ptr,之后不能再用ptr去操作这块内存(比如手动delete),否则会触发双重释放的未定义行为。这是unique_ptr的设计缺陷吗?
完全不是设计缺陷。unique_ptr的独占所有权是指禁止多个unique_ptr共享同一块内存的所有权,而非禁止原始指针与unique_ptr指向同一块内存。这种情况是你自己主动保留了原始指针导致的,unique_ptr的设计要求一旦将原始指针交给它管理,就不应再手动持有该原始指针。如何解决该问题?
最安全的解决方式是避免手动创建原始指针,直接使用std::make_unique创建unique_ptr,从源头杜绝重复持有指针的问题:
std::unique_ptr<foo> uptr = std::make_unique<foo>(5);
如果必须使用已有的原始指针构造unique_ptr,构造完成后立刻将原始指针置空,避免后续误操作:
foo *ptr = new foo(5); std::unique_ptr<foo> uptr(ptr); ptr = nullptr; // 置空原始指针,防止误操作
- std::make_unique()的作用是什么?我尝试将构造语句改为std::unique_ptr
uptr(std::make_unique (ptr));但结果未变。 std::make_unique是C++14引入的工具函数,核心作用是安全、便捷地创建unique_ptr*:它会在内部自动完成new操作,返回管理新对象的unique_ptr,既避免了手动写new的繁琐,也能规避内存泄漏、异常安全等问题。
你之前的用法是错误的:std::make_unique<foo>(*ptr)是拷贝ptr指向的对象,创建一个全新的foo实例,返回的unique_ptr管理的是这个新对象,而非接管ptr指向的原有对象。如果你想让unique_ptr接管已有原始指针,直接用std::unique_ptr<foo> uptr(ptr)即可(记得构造后置空ptr);如果是创建新对象,正确用法是std::make_unique<foo>(5),直接传递构造参数,无需手动处理指针。
内容的提问来源于stack exchange,提问作者Pisers

