• 智能指针(shared_ptr,unique_ptr)和动态分配的数组


    一,内存

    静态内存,栈内存,堆内存

    ①静态内存

    存储局部static对象和类的static对象以及定义在任何函数之外的变量

    ②栈内存

    栈内存用于保存定义在函数体内非static对象。

    ③堆内存

    运行需要创建时,才申请的内存空间,只有当程序结束时,才回收,也就是说我们如果不需要这个对象时,我们必须手动释放这块内存空间,否则造成内存泄漏

    智能指针

    ①智能指针可以在我们不需要动态申请的内存时,自动把这些内存归还给系统,防止了内存泄漏,
    而且我们通常会忘记delete动态申请的内存,
    ②当智能指针超出器范围时,就会自动析构,比如在代码块中定义的智能指针,程序执行到代码块之外就会自动析构智能指针

    二,shared_ptr

    shared_ptr允许多个指针同时指向同一个对象,默认初始化方式就是置为nullptr,使用前必须检查他是否是nullptr

    if(p && p->member_fun())
    {
    	// code
    }

    ①声明,初始化 (假设指针指向的对象类为T)

    最安全的分配和使用动态对象的方式是调用make_shared(args_list…)函数
    shared_ptr p = make_shard(args…)//相当于调用T对象的构造函数,args是其构造函数的参列 表,(如果仅声明就是调用默认构造器,直接置为nullptr)
    注意:如果shared_ptr对象的创建不可以用“=”直接赋值!!!,因为shared_ptr的构造器是explicit修饰的,指针不可以通过=直接转换为智能指针对象!!!,

    初始化的一些常见问题

    shared_ptr<int>  p1 = new int(1024);错误,因为shared_ptr的单参数构造器有explicit修饰,不能从内置类型直接转换成为对象!!,所以此行编译报错!!
    shared_ptr<int> p1(new int(1024));正确,调用了单参数构造器进行初始化,传入了指针初始化
     
    shared_ptr<int> f(int n)
    {
      return new int(n);同一个错误原因,explicit修饰了shared_ptr的构造器,无法从内置类型直接变成对象
    }

    ②shared_ptr的拷贝和赋值,计数器

    计数器递增的三种情况:
    ①用shared_ptr指针给同类的指针赋值,初始化
    ②作为函数实参传入函数
    ③作为函数返回值
    计数器递减:
    ①指针指向了另外一种对象(可能是T的子类),也就是发生在智能指针的赋值之间
    ②智能指针被销毁了,例如智能指针作为栈变量,出了代码块之后就被销毁了
    特别的:当引用计数器为0时,自动释放智能指针指向的内存空间
    也就是说当只有一个智能指针指向这块内存时,p被销毁,就会自动释放p指向的内存

    ③shared_ptr的使用:

    设计一个类叫Obj,Obj的一个成员就是shared_ptr指针,然后创建多个Obj的实例,初始化的时候就
    把需要共享的对象传进去,让shared_ptr指向同一个共享对象,就实现了共享,当没有对象的shared_ptr
    指向这个共享对象时,智能指针将自动释放动态的共享对象的内存并销毁它。
    shared_ptr内存示意图模型

    ④智能指针的陷阱

    	Ⅰ不使用相同的内置指针初始化或者reset多个智能指针,最好是用智能指针初始化智能指针
    	Ⅱ不delete get()返回的指针
    	Ⅲ不用get()初始化或reset另一个智能指针
    	Ⅳ使用get返回的指针,当唯一一个指向动态对象的智能指针销毁后,get指针也是失效了
    	Ⅴ当你使用智能指针管理的资源不是new分配时,记得传递一个删除器给智能指针

    三,unique_ptr

    unique_ptr则是独占这个对象,只能有一个指针指向这个对象

    四,动态分配的数组

    注:使用new分配的数组,只是返回了一个数组元素类型的指针,并没有得到一个数组对象,
    所以我们不可以对动态数组使用begin和end,以及范围for

    unique_ptr,shared_ptr和数组

    ①unique_ptr没有重载operator*()所以,要使用unique_ptr指向的数组的话,就只能使用operator[]来
    访问数组元素了,
    如图:

    #include <iostream>
    #include<memory>
    using namespace std;
    
    int main()
    {
    //    shared_ptr<int[]> ps(new int[1000]);由于默认是delete,所以禁止new [] 
        unique_ptr<int[]> ps(new int[99]);
        for(int i = 0 ; i < 10 ; i++)
            ps[i] = 10 - i;用operator[]访问数组元素,同时也没有operator*和operator++等
        for(int i = 0 ; i < 10 ; i++)
            cout << ps[i] << endl;
        return 0;
    }

    五,总结的一些警告

    new与new[]

    不要让auto_ptr和shared_ptr指向new[]申请的动态内存(除非为智能指针定义一个删除器)
    原因:auto_ptrshared_ptr 的默认释放内存方式是delete,如果动态对象是以new[] 形式创建的,比如数组,
    就不要使用auto_ptr和shared_ptr,否则就会导致以delete形式去释放new[]申请的内存
    一句话概括就是auto_ptr和shared_ptr只能指向new(除非为智能指针定义一个删除器)
    ② unique_ptr可以指向 new和new[] 申请的动态内存

     
  • 相关阅读:
    树莓派4B
    SpringBoot 自定义 info Actuator 原理
    RestTemplate翻译serviceId过程
    ISA, ABI, API区别
    01.编译器结构
    【Git123】Git SSH Key支持多账号
    【消息中间件123】Solace PubSub+ Event Broker介绍
    【ETL123】
    【Http123】Http Timeout
    【性能123】Linux性能之“平均负载”
  • 原文地址:https://www.cnblogs.com/lidabo/p/15831154.html
Copyright © 2020-2023  润新知