C++学习笔记03-智能指针(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则是独占这个对象,只能有一个指针指向这个对象

扫描二维码关注公众号,回复: 11485779 查看本文章

四,动态分配的数组

注:使用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[] 申请的动态内存

猜你喜欢

转载自blog.csdn.net/weixin_46028606/article/details/106956593