罗列出在使用智能指针的时候可能会犯的一些错误:
条款1:不要把一个原生指针给多个shared_ptr管理
int* ptr = new int;
shared_ptr<int> p1(ptr);
shared_ptr<int> p2(ptr);
在出作用域的时候,ptr的资源会被释放两次,把握的原则是:出了第一个shared_ptr用原生指针定义外,其后的所有操作都要以智能指针作为对象,在库中提供的几个转换操作符也是如此。
条款2:不要把this指针给shared_ptr
class Test{
public:
void Do(){ m_sp = shared_ptr<Test>(this); }
private:
shared_ptr<Test> m_sp;
};
Test* t = new Test;
shared_ptr<Test> local_sp(t);
p->Do();
出现了同条款一的问题,this指针被释放了两遍,不过如果正要实现指向自己的指针,boost库提供了该功能。
可以使用从enable_shared_from_this来实现,原理是在构造shared_ptr的时候已经构造了自己的观察者指针weak_ptr,从它构造即可。
include "boost/shared_ptr.hpp"
#include "boost/enable_shared_from_this.hpp"
class A;
void do_stuff(boost::shared_ptr<A> p) {
...
}
class A : public boost::enable_shared_from_this<A> {
public:
void call_do_stuff() {
do_stuff(shared_from_this());
}
};
int main() {
boost::shared_ptr<A> p(new A());
p->call_do_stuff();
}
上面代码实现了该功能,从weak_ptr构建了一个shared_ptr,引用计数加1,然后执行操作。
条款3:shared_ptr作为被保护的对象的成员时,小心因循环引用造成无法释放资源。
简单的例子:
class parent;
class children;
typedef boost::shared_ptr<parent> parent_ptr;
typedef boost::shared_ptr<children> children_ptr;
class parent
{
public:
~parent() { std::cout <<"destroying parent\n"; }
public:
children_ptr children;
};
class children
{
public:
~children() { std::cout <<"destroying children\n"; }
public:
parent_ptr parent;
};
void test()
{
boost::shared_ptr<parent> father( new parent);
boost::shared_ptr<children> son(new children);
father->children = son;
son->parent = father;
}
在test中出现了环引用计数,赋值后引用计数为2,出作用域后边为1,资源无法释放,发生内存泄露,所以虽然是智能指针,但是使用不当也会出现问题,boost库中的解决方法是利用weak_ptr指针来保存即可。
class parent
{
public:
~parent() { std::cout <<"destroying parent\n"; }
public:
boost::weak_ptr<children> children;
};
class children
{
public:
~children() { std::cout <<"destroying children\n"; }
public:
boost::weak_ptr<father> parent;
};
因为weak_ptr不影响引用计数。打破了这种环
条款4:不要在函数实参里创建shared_ptr
function ( shared_ptr<int>(new int), g( ) ); //有缺陷
可能的过程是先new int,然后调g( ),g( )发生异常,shared_ptr<int>没有创建,int内存泄露
shared_ptr<int> p(new int());
f(p, g()); //Boost推荐写法。
条款5:shared_ptr的类结构视图