首页 > 其他 > 详细

a review at smart pointer(4)

时间:2021-01-09 23:03:17      阅读:41      评论:0      收藏:0      [点我收藏+]

来源 https://www.cnblogs.com/jiayayao/p/6128877.html

#include "stdafx.h"
#include <iostream>
#include <future>
#include <thread>

using namespace std;
class Person
{
public:
    Person(int v) {
        value = v;
        std::cout << "Cons" <<value<< std::endl;
    }
    ~Person() {
        std::cout << "Des" <<value<< std::endl;
    }
    int value;
};

int main()
{
    std::shared_ptr<Person> p1(new Person(1));// Person(1)的引用计数为1
    std::shared_ptr<Person> p2 = std::make_shared<Person>(2);
    p1.reset(new Person(3));// 首先生成新对象,然后引用计数减1,引用计数为0,故析构Person(1)
                            // 最后将新对象的指针交给智能指针
    std::shared_ptr<Person> p3 = p1;//现在p1和p3同时指向Person(3),Person(3)的引用计数为2
    p1.reset();//Person(3)的引用计数为1
    p3.reset();//Person(3)的引用计数为0,析构Person(3)
    return 0;
}
  • 首先我们解释一下什么是引用计数,首先初始化一个shared ptr p1,然后其中的成员是new Person(1)
  • 内存布局可以理解为,一个heap区域的person类其地址为(假设为hp1),然后一个shared ptr在stack区,叫做p1
  • 然后同样的:heap区域的person类person(2)和其地址为hp2,然后一个shared ptr在stack区:p2
  • p1 reset一个new person(3), 这个的解释过程为:首先在heap区new一个person 3,其地址为hp3,然后,执行reset函数,因为reset的目的永远是释放一个count,所以count - 1变成0,然后析构person(1),所以,hp1消失,然后hp3交给p1,count自增
  • 然后复制一个shared ptr p3,值是p1,里面的内容也是一样的, 我们发现hp3既交给了p1也交给了p3,count为2
  • p1.reset, count--
  • p3.reset, count--

所以我们可以发现,share ptr的share为什么是share? 它代表的是多个share指针共享一个堆资源

之后我有个硕大的疑问

  • 来源某pp prime的一句话:shared_ptr自动销毁所管理的对象
    当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象,它是通过另一个特殊的成员函数-析构函数完成销毁工作的,类似于构造函数,每个类都有一个析构函数。析构函数控制对象销毁时做什么操作。析构函数一般用来释放对象所分配的资源。shared_ptr的析构函数会递减它所指向的对象的引用计数。如果引用计数变为0,shared_ptr的析构函数就会销毁对象,并释放它所占用的内存。
  • 然后不仅仅是这一个博客上有说:不要用一个原始指针初始化多个shared_ptr,原因在于,会造成二次销毁
    int *p5 = new int;
    std::shared_ptr<int> p6(p5);
    std::shared_ptr<int> p7(p5);// logic error
  • 上述代码很好理解,二次销毁谁不知道

我的问题是,这篇文章的第一份代码不也是两个指针指向一个资源吗?为什么这个就没有错呢?

答案是:第一份代码是两个智能指针有着一模一样的值,它是shared ptr(语义上),指向一个资源,它们在stack区域的值是一模一样的,=之间应该是有运算符重载的机制让count自增(代表了shared,所以count自增)

但是第二个例子不对的地方在于,它并不是智能指针的赋值,它是让一个指针进入两个构造函数,所以count应该是无自增的机制的

第一个例子由shared ptr自己的机制进行垃圾回收,根据count何时减到0

  • 另外,不要在函数实参中创建shared_ptr
// 错
function(shared_ptr<int>(new int), g());

通过查阅文档我们发现unique ptr的默认删除器是支持释放数组对象的,如: std::unique_ptr<int[]> foo (new int[5]); 但是shared ptr 不支持[] ,所以我们要自定义deleter

关于到底是int[]还是int,自定义(不自定义)deleter的问题,我直说了: 我看不懂,因为20,17,11三个版本的要求全不一样,感兴趣的参见这篇博客 https://www.cnblogs.com/apocelipes/p/10346928.html 到时候开发就现查文档

  • 另外,注意unique ptr可以转shared ptr,反过来不可,比如
#include <iostream>
#include <memory>
using namespace std;

class A{
public:
    string id;
    A(string id):id(id){cout<<id<<":构造函数"<<endl;}
    ~A(){cout<<id<<":析构函数"<<endl;}
};

int main() {
    unique_ptr<A> a(new A("unique_ptr"));
    shared_ptr<A> b = move(a);
//    a = move(b);  // 报错
//    a.reset(b.get());  // 运行错误
    cout<<a.get()<<endl;
    return 0;
}
  • 用get拿到智能指针的裸指针之后删掉它,会导致智能指针运行错误

  • 不要用stack中的变量地址初始化一个smart pointer

#include <iostream>
#include <memory>
using namespace std;

class A{
public:
    string id;
    A(string id):id(id){cout<<id<<":构造函数"<<endl;}
    ~A(){cout<<id<<":析构函数"<<endl;}
};

A a("全局变量");

int main() {
    A b("局部变量");
//    unique_ptr<A> pa(&a); // 运行错误
    unique_ptr<A> pa(&b);
    return 0;
}

谨慎使用智能指针的get与release方法

  • 通过unique_ptr.release()方法返回的裸指针,需要我们自己delete删除对象,因为调用release方法后,该unique_ptr不再拥有对象的所有权。

循环引用问题待更

a review at smart pointer(4)

原文:https://www.cnblogs.com/sjl473/p/14255830.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!