移动std::shared_ptr管理的std::unique_ptr是否存在安全风险?
结论
你的代码是安全的,不会出现shared_ptr删除悬空对象的问题。
两个智能指针的行为拆解
你需要先明确一个核心区分:std::shared_ptr在这里管理的是**std::unique_ptr<ISomeInterface>类型的堆对象**,而非ISomeInterface实例本身,移动操作不会导致被shared_ptr管理的对象悬空。
整个流程的行为完全符合C++标准:
- 调用
std::make_shared时,会在堆上构造一个std::unique_ptr<ISomeInterface>对象,它持有传入的ISomeInterface实例的所有权,shared_ptr的职责是管理这个堆上unique_ptr对象的生命周期。 - lambda按值捕获
shared_ptr后,只要lambda还未销毁,shared_ptr的引用计数就不会归零,它管理的unique_ptr对象会一直有效。 - lambda执行时,
std::move(*sharedPtr.get())会触发unique_ptr的移动构造:将堆上unique_ptr持有的ISomeInterface所有权转移给局部变量unique,此时堆上的unique_ptr会被置为空,但它本身作为一个对象是完整、合法存在的,不存在悬空情况。 - 回调
cb执行完毕后,lambda销毁,持有的shared_ptr被释放,如果此时该shared_ptr的引用计数归零,会销毁它管理的那个已经为空的unique_ptr对象:销毁空unique_ptr是完全合法的操作,不会尝试释放已经被转移走的ISomeInterface实例,也不会触发任何内存错误。
唯一注意事项
该实现仅适用于回调只会被触发一次的场景:如果GetSomethingAsync会多次调用传入的回调,那么第一次调用就会把shared_ptr管理的unique_ptr移空,后续调用拿到的都是空unique_ptr,如果回调没有做空指针判断就会出错。你当前使用的异步回调场景通常只会触发一次,因此没有问题。
内容的提问来源于stack exchange,提问作者mario.b
相关产品推荐
相关产品推荐

