一,内存
静态内存,栈内存,堆内存
①静态内存
存储局部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
指向这个共享对象时,智能指针将自动释放动态的共享对象的内存并销毁它。
④智能指针的陷阱
Ⅰ不使用相同的内置指针初始化或者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_ptr 和 shared_ptr 的默认释放内存方式是delete,如果动态对象是以new[] 形式创建的,比如数组,
就不要使用auto_ptr和shared_ptr,否则就会导致以delete形式去释放new[]申请的内存
一句话概括就是auto_ptr和shared_ptr只能指向new(除非为智能指针定义一个删除器)
② unique_ptr可以指向 new和new[] 申请的动态内存