Chinaunix首页 | 论坛 | 博客
  • 博客访问: 82629
  • 博文数量: 18
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 321
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-30 21:09
文章分类

全部博文(18)

文章存档

2015年(3)

2014年(9)

2013年(6)

我的朋友

分类: C/C++

2014-01-27 13:23:31

注明:这篇文章的例子来自于网络,但主要的内容是分享自己对于智能指针使用上的一些心得,因此还是将这篇文章规为了原创;
例子的博文引用自:
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;


阅读(1080) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~