C++智能指针

auto_ptr
由于auto_ptr被销毁时会自动删除它所之物,所以一定要注意别让多个auto_ptr指向同一个对象。如果真的是那样,对象会被删除一次以上,而那会是你的程序搭上“未定义行为”的快速列车上,为了预防auto_ptrs,有一个不同寻常的性质:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,从而复制所得的指针将取得资源的唯一拥有权
这是一个诡异的复制行为,附加上其底层条件:“受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向它”,意味着auto_ptrs并非管理动态资源的神兵利器。
shared_ptr

auto_ptr的替代方案是“引用计数智能指针(reference_counting smart pointer;RCSP)”。RCSP持续追踪有多少个对象指向某笔资源,并在无人指向它时自动删除该资源。

多个shared_ptr对象可能拥有同一个对象。当以下任一情况发生时,对象将被销毁并释放其内存:

  • 最后剩下的shared_ptr拥有该对象的对象被销毁;
  • 最后一个shared_ptr拥有该对象的人通过operator=或reset()分配了另一个指针。

在典型的实现中,shared_ptr只保存两个指针:

  • 存储的指针(由get()返回的指针);
  • 指向控制块的指针。

控制块是一个动态分配的对象,它包含:

  • either a pointer to the managed object or the managed object itself;
  • 删除器;
  • 分配器;
  • the number of shared_ptr that own the object;
  • the number of weak_ptr that own the object;

当shared_ptr通过调用std::make_shared或std::allocate_shared创建时,控制块和托管对象的内存都是使用单个分配创建的。托管对象在控制块的数据成员中就地构造。
在这里插入图片描述

当shared_ptr通过shared_ptr构造函数之一创建时,必须分别分配托管对象和控制块。在这种情况下,控制块存储一个指向被管理对象的指针。

在这里插入图片描述

shared_ptr直接持有的指针是get()返回的指针,而控制块持有的指针/对象是当共享所有者的数量达到零时将被删除的指针/对象。这些指针不一定相等。

shared_ptr的destructor减少控制块的共享所有者的数量。如果该计数器达到零,则控制块调用destructor of the managed object。在std::weak_ptr计数器也达到零 之前,控制块不会自行释放。

weak_ptr
weak_ptr持有对std::shared_ptr管理的对象的非拥有(“弱”)引用。必须将其转换为shared_ptr才能访问引用的对象

weak_ptr建模临时所有权:当一个对象只有在它存在时才需要访问,并且它可能被其他人随时删除,weak_ptr用于跟踪该对象,并将其转换为std::shared_ptr以承担临时所有权。如果此时原始std::shared_ptr被销毁,则对象的生命周期会延长,直到临时std::shared_ptr也被销毁。

weak_ptr的另一个用途是打破由std::shared_ptr管理的对象形成的引用循环。如果这样的循环是孤立的(即循环中没有外部共享指针),则shared_ptr引用计数不能达到零并且内存泄漏。为了防止这种情况,可以将循环中的指针之一设置为 weak。

与shared_ptr一样,weak_ptr存储两个指针 的典型实现:

  • 指向控制块的指针
  • shared_ptr的存储

在这里插入图片描述

当 shared_ptr 析构并释放共享资源的时候,只要 weak_ptr 对象还存在,控制块就会保留,weak_ptr 可以通过控制块观察到对象是否存活。
在这里插入图片描述
循环引用问题

class parent;
class children;


class parent
{
public:
    ~parent() { std::cout << "destroying parent\n"; }

public:
    //weak_ptr<children>  children;
    shared_ptr<children> children;
};

class children
{
public:
    ~children() { std::cout << "destroying children\n"; }

public:
    shared_ptr<parent> parent;
    //weak_ptr<parent>  parent;
};

void test()
{
    shared_ptr<parent> father(new parent);
    shared_ptr<children> son(new children);

    father->children = son;
    cout << son.use_count() << endl;

    son->parent = father;
    cout << father.use_count() << endl;
}

void main()
{
    std::cout << "begin test...\n";
    test();
    std::cout << "end test.\n";
    cin.get();
}

parent 类中有指向children 类的shared_ptr智能指针,children 类中有指向parent类的shared_ptr 智能指针,他们相互指向会构成shared_ptr 的循环引用。

利用weak_ptr就可以解决循环引用的问题,因为weak_ptr是弱引用型指针,是用来监视shared_ptr的,不会使引用计数增加,但是它不管理shared_ptr内部的指针,也就是数据指针,它是用来监视shared_ptr生命周期的,通过它的构造不增加引用计数,析构不减少引用计数这一点,从而解决了循环引用的问题。

class parent
{
public:
    ~parent() { std::cout << "destroying parent\n"; }

public:
    weak_ptr<children>  children;
    //shared_ptr<children> children;
};

class children
{
public:
    ~children() { std::cout << "destroying children\n"; }

public:
    shared_ptr<parent> parent;
};

void test()
{
    shared_ptr<parent> father(new parent);
    shared_ptr<children> son(new children);
	
    father->children = son;
    cout << son.use_count() << endl;

    son->parent = father;
    cout << father.use_count() << endl;
}

void main()
{
    std::cout << "begin test...\n";
    test();
    std::cout << "end test.\n";
    cin.get();
}

转自https://zhuanlan.zhihu.com/p/150555165

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值