用本地裸指针初始化std::unique_ptr是否安全?已知std::shared_ptr此操作不明智
用本地裸指针初始化std::unique_ptr是否安全?
首先直接给结论:用未被其他所有权机制管理的本地裸指针初始化std::unique_ptr本身是安全的,但关键在于初始化之后的行为——你必须立刻放弃对这个裸指针的直接使用,因为unique_ptr已经接管了对象的独占所有权。
为什么和std::shared_ptr不一样?
std::shared_ptr的问题在于它是共享所有权模型,如果你用同一个裸指针初始化多个shared_ptr,每个shared_ptr都会创建自己的控制块,最终导致对象被多次析构,这是严重的未定义行为。但std::unique_ptr是独占所有权设计,它确保同一时间只有一个unique_ptr拥有对象的所有权,所以用裸指针初始化它的时候,只要这个裸指针没有被其他智能指针或代码持有所有权,就不会有重复析构的问题。
你的示例代码里的风险点
来看你给出的代码:
class A { public: void do_something() { } }; std::vector<std::unique_ptr<A>> uq_ptrs_; auto p = new A(); uq_ptrs_.push_back(std::unique_ptr<A>(p)); p->do_something(); // 这里有风险!
这段代码的问题不是初始化unique_ptr的行为不安全,而是在unique_ptr接管对象所有权之后,你仍然通过裸指针p访问对象。此时:
- 虽然
p->do_something()在当前场景下可能暂时不会崩溃(因为对象还没被销毁),但你已经失去了对对象生命周期的控制权。比如,如果之后uq_ptrs_被清空,或者其中的元素被移除,p就会变成悬空指针,再使用它就会触发未定义行为。 - 更稳妥的做法是要么在初始化unique_ptr后立刻丢弃裸指针,要么直接在push_back的时候构造unique_ptr,避免裸指针的存在:
// 方式1:直接构造,不保留裸指针(推荐) uq_ptrs_.push_back(std::make_unique<A>()); // 方式2:如果需要先操作对象再放入容器 auto ptr = std::make_unique<A>(); ptr->do_something(); uq_ptrs_.push_back(std::move(ptr));
用std::make_unique是更推荐的方式,它完全避免了裸指针的暴露,从根源上消除了风险。
总结
- 用未被其他所有权管理的裸指针初始化unique_ptr是安全的,但这不是最佳实践(最佳实践是用make_unique)。
- 初始化后绝对不能再使用原来的裸指针,因为对象的所有权已经转移给unique_ptr,你不再拥有操作它的权限。
- 和shared_ptr的核心区别在于unique_ptr的独占所有权模型,不会出现多个智能指针同时管理同一个对象的情况。
内容的提问来源于stack exchange,提问作者duong_dajgja
相关产品推荐
相关产品推荐

