命名空间中用shared_ptr作变量:是否存在悬垂指针与未定义行为?
代码分析与安全性验证
class A { public: A(const std::shared_ptr<B> params_); private: const std::shared_ptr<B> params; void fun1(); }; A::A(const std::shared_ptr<B> params_) : params(params_) {} void A::fun1() { calc::fun2(params); } namespace calc { std::shared_ptr<B> params; void fun2(const std::shared_ptr<B> & params_) { calc::params = params_; //... } } int main() { //create instance of A and call calc::fun2() }
悬垂指针/引用安全性
从悬垂指针角度看,这段代码不会产生悬垂问题:
- 类A的
params和命名空间calc的params都是std::shared_ptr<B>类型,当calc::fun2把传入的params_赋值给calc::params时,shared_ptr会自动增加B对象的引用计数。只要任意一个shared_ptr还持有B的引用,B对象就不会被销毁,也就不存在悬垂指针/引用的情况。
内存泄漏风险
这段代码存在潜在的内存泄漏风险:
calc::params是全局变量,一旦它持有了B对象的引用,即使所有A的实例都被销毁,只要calc::params没有被显式调用reset()或者赋值为空,B对象就会一直存在,直到程序结束。如果B是占用大量资源的对象,或者需要在A销毁后及时释放,这就会导致资源无法及时回收,形成内存泄漏。- 额外要排查大型程序中是否存在循环引用:如果B类内部也持有
std::shared_ptr<A>,那么A和B的shared_ptr会形成循环引用,导致两者的引用计数永远无法归零,最终造成内存泄漏。当前给出的代码中没有这种情况,但实际项目中需要确认。
额外注意事项
- 全局的
calc::params在多线程环境下访问时需要加锁,否则会出现线程安全问题(比如多个线程同时赋值或访问)。 - 如果
calc::fun2只是临时使用B对象,不需要长期持有,建议直接使用传入的params_引用,不要赋值给全局的calc::params,这样可以避免不必要的引用计数增加,降低内存泄漏风险。
内容的提问来源于stack exchange,提问作者SolidMechanicsFan
相关产品推荐
相关产品推荐

