C++——第四章 智能指针

PS:仅供自己记录笔记,使用到时进行记录,不具有参考性。

1. 直接内存管理

(1) new分配方式我们称为 动态分配(分配在堆上):直接内存管理(new / delete)。new和delete分别调用构造函数和析构函数。
// 初始化
string *mystr = new string; //空字符串,调用了string的默认构造函数
int *pointi = new int(100); // 用()给一个int的动态对象初值
string *mystr2 = new string(5, 'a); // 生成一个字符串,字符串内容是5个'a'
vector *pointv = new vector{1,2,3,4,5};
// 值初始化  + (), 一般用值初始化,防止它的值没有被初始化。
string *mystr3 = new string(); 
  • 有new一定要有delete。delete后的内存不能再使用,否则异常。delete一个柱指针后,一般将该指针 == nullptr。
  • 同一块内存释放两次,也会报异常。

2. 智能指针

  • 裸指针:直接使用new返回的指针,需要全程负责维护。
  • 智能指针:解决裸指针代码的各种问题。对裸指针进行了包装,智能指针能够自动释放所指向的对象内存,优先算选择智能指针。
  • 有四种智能指针:auto_ptr(C++98,已经完全呗unique_ptr取代,不要使用!), unique_ptr, shared_ptr, weak_ptr。这三种智能指针都是类模板。
  • shared_ptr:共享式指针,多个指针指向同一个对象,最后一个指针被销毁时,这个对象会被释放,weak_ptr 是辅助shared_ptr工作的。
  • unique_ptr:独占式指针,同一个时间内,只有一个指针能够指向该对象。当然该对象的所有权还是可以移交出去的。
(1) shared_ptr
  • 共享所有权,被多个share_ptr之间相互协作,有额外开销。
  • 原理:引用计数,每个share_ptr的拷贝都指向相同的内存。所以只有引用计数为0,shared_ptr才会析构这个对象。
  • 当shared_ptr被析构 或者 shared_ptr指向其他对象时,其原来指向的对象会被释放。不用担心对象何时需要delete。
// pi指向一个值为100的int类型数据
shared_ptr pi(new int(100));

// 下面错误智能指针时explicit,使用=号就进行隐式类型转换了,必须直接初始化。
// shared_ptr pi2 = new int(200);

shared_ptr pi; // 空指针,nullptr
  • make_shared: 安全、高效的使用shared_ptr。能够在动态内存(堆)中分配并初始化一个对象,然后返回指向此对象的shared_ptr、
shared_ptr p2 = make_shared(100);
  • 引用计数增加::每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象。使用shared_ptr初始化另外一个指针或把智能指针当做实参往函数里传递(值传递),所有指向这个对象的shared_ptr的引用计数都会增加。引用传递不会增加。
  • 引用计数减少:给shared_ptr赋予新值,让shared_ptr指向一个新的对象。 局部的shared_ptr离开其作用域。
  • use_count(): 返回多少个智能指针指向某个对象,主要用于调试。
  • unique():是否该指针独占某个指向的对象,只有一个智能指针指向某个对象,则unique()返回ture。
  • reset():恢复,复位,重置。不带参数时:若pi是唯一指向该对象的指针,那么释放pi所指向的对象,并将pi置空;若pi不是唯一,那么不释放pi所指向的对象,但计数会减少1,同时将pi置为空。带参数时:参数一般是一个new出来的指针。若pi是唯一指向该对象的指针,释放该对象,让pi指向新对象;若不唯一,则不释放对象,但引用计数减1,同时让pi指向新对象。空指针也可以通过reset来重新初始化,shared_ptr p; p.rest(new int(1));
  • *解引用:获得p指向的对象。
  • get():返回p中保存的指针(裸指针)。考虑到有些函数需要的是一个内置的裸指针而不是智能指针,,不要delete返回的裸指针,因为智能指针会管理。
  • swap():交换两个智能指针所指向的对象。std::swap(p1, p2); 或者 p1.swap(p2);
  • =nullptr:将所指向的对象引用计数减1,若引用计数变为0,释放该对象。将智能指针置空。
(2) weak_ptr
  • 指向由一个shared_ptr管理的对象,weak_ptr不会改变绑定到shared_ptr的对象的引用计数。其不是一个独立的智能指针,是辅助shared_ptr。相当于辅助、监测。
  • 创建:使用shared_ptr进行初始化。
auto pi = make_shared(100);
weak_ptr piw(pi); // piw引用计数,强引用计数才绝对对象的声明周期。
  • lock(): 检查weak_ptr所指向的对象是否存在,如果存在,就返回一个指向该对象的shared_ptr(强引用计数+1)
auto pi2 = piw.lock(); // pi2是一个shared_ptr
if(pi2 != nullptr)
{
	// 说明所指对象存在
	*pi2 = 12;
}
  • use_count(): 获取该弱指针所指向对象的shared_ptr的数量。
  • expired(): 是否过期的意思,该弱指针的use_count() 为0(表示弱指针所指向的对象已经不存在了),则返回true。即判断所观测的对象资源是否已经被释放。
(4) unique_ptr
  • 独占式智能指针,同一时刻只有一个unique_ptr指向这个对象(这块内存),当这个unique_ptr被销毁时,它所指向的对象也被销毁。
  • 常规初始化:
unique_ptr pi; //指向int类型的空智能指针 nullptr
unique_ptr pi2(new int(105)); //pi2指向一个105的int对象
  • make_unique函数:
unique_ptr p1 = make_unique(105);
  • unique_ptr不支持的操作:不支持赋值、拷贝动作。
unique_ptr ps1(new string("I Love China!"));
//unique_ptr ps2(ps1); //不支持拷贝动作,定义时初始化
//unique_ptr ps3 = ps1; //不支持拷贝动作,定义时初始化
  • 移动语义:移动到另外一个独占式指针中
unique_ptr ps1(new string("I Love China!"));
unique_ptr ps2 = std::move(ps1); //移动完后,ps1为空,ps2指向原来ps1所指。
  • release(): 放弃对指针的控制权,切断智能指针和其所指向的对象之间的联系。返回裸指针,将该智能指针置空。返回的这个裸指针我们可以手工delete释放。
  • reset():不带参数情况下,释放智能指针所指的对象,并将智能指针置空。带参情况下:
unique_ptr ps2(new string("I Love China!"));
ps1.reset(ps2.release());  // reset释放ps1所指向的对象内存,让ps1指向ps2所指向的内存,同时ps2被置空。
  • get():返回智能指针中保存的裸指针。
  • *解引用:获取该智能指针指向的对象,可以直接操作;
  • swap():交换两个智能指针所指向的对象。
unique_ptr ps1(new string("I Love China1!"));
unique_ptr ps2(new string("I Love China2!"));
std::swap(ps1, ps2);
ps1.swap(ps2);
(5) 智能指针的选择(shared_ptr, unique_ptr)
  • 如果程序要使用多个指向同一个对象的指针,应该选择shared_ptr;
  • 如果程序不需要多个指向同一个对象的指针,应该选择unique_ptr;

你可能感兴趣的:(C++,c++,算法,开发语言)