注明:这篇文章的例子来自于网络,但主要的内容是分享自己对于智能指针使用上的一些心得,因此还是将这篇文章规为了原创;
例子的博文引用自:
http://www.cnblogs.com/TianFang/archive/2008/09/20/1294590.html
http://blog.chinaunix.net/blog/post.html
使用shared_ptr时,若使用不当,会产生释放死锁,导致内容泄露。比如下面的这个简单例子:
#include
#include
#include
#include
class parent;
class children;
typedef boost::shared_ptr parent_ptr;
typedef boost::shared_ptr 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()
{
parent_ptr father(new parent());
children_ptr son(new children);
father->children = son;
son->parent = father;
}
int main()
{
std::cout<<"begin test...\n";
test();
std::cout<<"end test.\n";
return 0;
}
在上面这段代码中,child对象的释放依赖于parent对象被析构;而parent对象被释放,又依赖于child对象被释放,因此形成了一个死锁,导致内存泄漏;
解决这个问题,一个简单的办法就是在一个对象中使用weak_ptr,使得这种死锁的条件存在。比如修改以下代码,如下:
class children
{
public:
~children() { std::cout <<"destroying children\n"; }
public:
boost::weak_ptr parent;
};
在这个情况下,由于child对parent的持有不是shared,不拥有控制权,因此parent对象在函数结束后就被析构了;parent析构时,释放了child的控制权,因此child也被释放了;
另外一种情况,就是自己的类里面包含自己的shared_ptr,也会导致死锁,比如:
class StupidSharedPtr
{
public:
~StupidSharedPtr() { std::cout << "destroying StupidSharedPtr\n"; }
public:
boost::shared_ptr _stupid_shared_ptr;
};
void test()
{
boost::shared_ptr stupid_shared_ptr(new StupidSharedPtr());
stupid_shared_ptr->_stupid_shared_ptr = stupid_shared_ptr;
}
为什么要有tr1::enable_shared_from_this这个类
这个问题,我们可以这么思考,给你一个对象,你怎么给我这个对象的shared_ptr;第一种给法如下:
class StupidSharedPtr
{
public:
~StupidSharedPtr() { std::cout << "destroying StupidSharedPtr\n"; }
public:
boost::shared_ptr get_shared()
{
boost::shared_ptr ret(this);
return ret;
}
public:
boost::shared_ptr _stupid_shared_ptr;
};
void test2()
{
boost::shared_ptr stupid_shared_ptr1(new StupidSharedPtr());
StupidSharedPtr& r = *stupid_shared_ptr1;
boost::shared_ptr stupid_shared_ptr2 = r.get_shared();
}
若采用这种做法,则会出现doulble free,对同一个对象析构两次,因为虽然两个shard_ptr指向同一个对象,但两个shard_ptr各顾各的,互不认识,各自管理了自己的引用计数,因此会出现double free的现象;
看了这个之后,很快会有人提出一种新的方法来,如下:
class StupidSharedPtr
{
public:
StupidSharedPtr():_stupid_shared_ptr(this) {}
~StupidSharedPtr() { std::cout << "destroying StupidSharedPtr\n"; }
public:
boost::shared_ptr get_shared()
{
return _stupid_shared_ptr;
}
public:
boost::shared_ptr _stupid_shared_ptr;
};
不好意思,这种做法如前面分析,会导致对象释放的死循环!
正确的做法为:
class StupidSharedPtr : public enable_shared_from_this
{
public:
~StupidSharedPtr() { std::cout << "destroying StupidSharedPtr\n"; }
};
void test2()
{
boost::shared_ptr stupid_shared_ptr1(new StupidSharedPtr());
StupidSharedPtr& r = *stupid_shared_ptr1;
boost::shared_ptr stupid_shared_ptr2 = r.shared_from_this();
}
enable_shared_from_this内部是用weak_ptr实现的,后续再做深入的分析
总结:shared_ptr和weak_ptr的使用场景
上面也分析了shared_ptr的很多弊端,shared_ptr不能乱用,否则导致的内存泄漏将很难查出来;
在有些场合反而是weak_ptr更加适合,但这里的原则到底是什么呢?
1. 若需要对资源做强制的控制,比如说未经允许,资源绝对不能释放,那么毫无疑问,必须用shared_ptr;
2. 若资源存在时,利用一下;资源不存在了,那就不利用了;也就是说对资源没有强制的控制需求,那么可以用weak_ptr;
阅读(1106) | 评论(0) | 转发(0) |