1.动态内存
- 定义:new在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete接受一个动态对象的指针销毁该对象,并释放与之关联的内存。
- 存在的问题:当多次释放动态分配的内存时,导致引用非法内存的指针;当忘记释放动态分配的内存时,会导致内存泄露。
- 智能指针本质:避免悬空指针的产生。
2.shared_ptr类
2.1 shared_ptr意义
- 意义:shared_ptr实现共享式拥有,多个智能指针可以指向相同对象,使用计数机制来表明资源被几个指针共享,该对象和其相关资源会在最后一个引用被销毁时候释放。同时因为智能指针是一个类,当超出对象的作用域时,会自动调用对象的析构函数,释放相关资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间。
2.2 shared_ptr定义和初始化
- 智能指针和普通指针区别:对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,因为普通指针是指针,智能指针是类,类型不一致。可以通过make_shared函数或者通过构造函数传入普通指针,并且可以通过get函数获得普通指针。
- shared_ptr定义及初始化:调用make_shared的标准库函数
shared_ptr<int> p1 = make_shared<int>(42);
shared_prt<string> p2 = make_shared<string>(10,'9');
shared_prt<int> p3 = make_shared<int>();
auto p4 = make_shared<vector<string>>();
shared_ptr<Person> p(new Person());
2.3 shared_ptr的use_count成员函数
- 引用计数user_count:
int count = p.user_count();
。智能指针类能记录有多少个shared_ptr 指向相同的对象,并能在恰当的时候自动释放对象。
- 关联的计数器(引用计数)递增一的情况:可以和调用拷贝构造函数类比。
a.用一个shared_ptr初始化另一个shared_ptr;
b.shared_ptr作为参数传递给一个函数 ;
c.shared_ptr作为函数的返回值。
- 关联的计数器(引用计数)递减一的情况:
a.给shared_ptr赋值一个新值 (operator= 或 reset() 赋值);
b.shared_ptr被销毁(例如局部的shared_ptr离开其作用域)。同时如果一个shared_ptr的计数器变为0,就会释放自己所管理的对象。例如:
auto r = make_shared<int>(42);
r = q;
2.4 shared_ptr拷贝和赋值
- 当进行拷贝和赋值操作时,每个shared_ptr都会记录有多少个shared_ptr 指向相同的对象。例如,
auto p = make_shared<int>(42);//p指向的对象只有p一个引用者;
auto q(p);//或者auto q=p; p和q指向相同的对象,此对象有两个引用者;
2.5 shared_ptr删除
- 分离关联的原始指针:要使 shared_ptr 对象取消与相关指针的关联,可以使用reset()函数:
- 不带参数的reset():
p1.reset();
,它将引用计数减少1,如果引用计数变为0则删除指针。
- 带参数的reset():
p1.reset(new int(34));
,在这种情况下,它将在内部指向新指针,因此其引用计数将再次变为1。
- 使用nullptr重置:
p1 = nullptr;
- 自定义删除器deleter:有些时候在析构函数中,delete函数并不能满足我们的需求,可能还想加其他的处理。例如:当 shared_ptr 对象指向数组
shared_ptr<int> p(new int[12]);
,像这样申请的数组,应该调用delete []释放内存,而shared_ptr析构函数中默认delete并不能满足需求。因此需要给shared_ptr添加自定义删除器,这种情况下可以将回调函数传递给shared_ptr 的构造函数,该构造函数将从析构函数中调用以进行删除。即
void del(Person *x){
cout << "DELETER FUNCTION CALLED\n";
delete[] x;
}
shared_ptr<Person> p(new Person[12], del);