boost智能指针shared_ptr使用要注意的几个问题

本文通过实例分析了boost库中的shared_ptr在使用时可能出现的错误,特别是涉及循环引用的情况,导致的对象无法正确析构和内存泄漏问题。通过调整代码避免在构造函数中直接设置依赖关系,可以解决这个问题。
摘要由CSDN通过智能技术生成

boost库中的shared_ptr是个好东西,一度我认为可以像C#那样使用对象,完全不用考虑内存的释放问题。不过使用起来发现还是有许多要注意的地方。

首先,绝对不可以像这样使用:


 

这个看上去很简单,一般都不会这样犯错误。但如果在一个复杂的场景中呢?比如这样:



在这里,我考虑设计一个简单的发布/定购的模式,为了简化内存管理,应用了shared_ptr。看上去好像没什么问题,
但实际并非如此,当shared_ptr_test()执行结束时会报错:

"Unhandled exception at ...: 0xC0000005: Access violation writing location 0xfeeefef2."

为什么?
这个错误太隐蔽了,问题出现在CConcreteListener的构造函数中。
这两行代码:
boost::shared_ptr<CConcreteListener> concreteListener1 (new CConcreteListener (publisher1));
和CConcreteListener构造函数中的
m_publisher->SetListener (boost::shared_ptr<CListener> (this));

如果展开用另一种方式看的话,相当于这样:
CConcreteListener *p1 = new CConcreteListener;
boost::shared_ptr<CListener> sp1 (p1);
publisher1->SetListener (sp1);
boost::shared_ptr<CConcreteListener> concreteListener1 (p1);

哦,看上去和上面那个例子犯了同样的错误,不过这里更隐蔽,更不容易发现。

那么我们改动一下,把
m_publisher->SetListener (boost::shared_ptr<CListener> (this));
从CConcreteListener的构造函数中移出去,然后在shared_ptr_test()中这样使用:



也就是在外面显式调用SetListener,恩,这回上面那个问题消失了,程序不会崩溃了。
这回正确了?看看程序的输出把:
CPublisher::CPublisher()
CConcreteListener::CConcreteListener ()
CConcreteListener::TakeAction()

好像有点问题,shared_ptr_test()函数已经结束了,publisher1和concreteListener1都已经过了生命期,应该析构销毁了,
那他们内部的的CPublisher和CConcreteListener对象也应该被释放呀,但没看到这两个类的析构函数被调用。

如果跟踪函数的调用,会发现当publisher1和concreteListener1结束生命期析构后,内部的引用计数都是1,导致内部引用对象无法释放。
这是由于两个类CPublisher和CConcreteListener中存在循环引用。
由于shared_ptr是通过引用计数管理对象,他是无法处理循环引用的问题,导致有些对象永远无法从内存中释放。
所以,使用shared_ptr,还必须小心循环引用的问题。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值