C++学习——动态内存与智能指针
动态内存与智能指针
动态内存的管理是通过一对运算符来完成:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对对象进行初始化:delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
为了更容易(同时也更安全)地使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象。
智能指针与常规指针的区别是它负责自动释放所指向的对象。
新标准库提供的这两种智能指针的区别在于管理底层指针的方式:
- shared_ptr 允许多个指针指向同一个对象;
- unique_ptr 则“独占”所指向的对象。
还定义了一个名为 weak_ptr 的伴随类,它是一种弱引用,指向 shared_ptr 所管理的对象。
这三种类型都定义在 memory 头文件中。
shared_ptr 类
智能指针也是模板。
当创建一个智能指针时,必须提供额外的信息——指针可以指向的类型。
在尖括号内给出类型,之后是所定义的这种智能指针的名字:
shared_ptr<string> p1; // shared_ptr,可以指向 string
shared_ptr<list<int>> p2; // shared_ptr,可以指向 int 的 list
默认初始化的智能指针中保存着一个空指针。
智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。
如果有一个条件判断中使用智能指针,效果就是检测它是否为空:
// 如果p1不为空,检查它是否指向一个空 string
if (p1 && P1->empty())
*p1 = "hi"; // 如果p1指向一个空 string,解引用p1,将一个新值赋予 string
make_shared 函数
最安全的分配和使用动态内存的方法。
此函数在动态内存中分配一个对象并初始化它,返回指向此对象的 shared_ptr。
与智能指针一样,make_shared 也定义在头文件 memory 中。
当要用 make_shared 时,必须指定想要创建的对象的类型。
定义方式与模板类相同,在函数名之后跟一个尖括号,在其中给出类型:
// 指向一个值为42的int的shared_ptr
shared_ptr<int> p3 = make_shared<int>(42);
// p4指向一个值为“9999999999”的string
shared_ptr<string> p4 = make_shared<string>(10, '9');
//p5指向一个值初始化的 int,即,值为0
shared_ptr<int> p5 = make_shared<int>();
通常用 auto 定义了一个对象来保存 make_shared 的结果,这种方式较为简单:
// p6 指向一个动态分配的空 vactor<string>
auto p6 = make_shared<vector<string>>();
shared_ptr 的拷贝和赋值
当进行拷贝或赋值操作时,每个 shared_ptr 都会记录有多少个其他 shared_ptr 指向相同的对象:
auto p = make_shared<int>(42); //p指向的对象只有p一个引用者
auto q(p); // p 和 q指向相同对象,此对象有两个引用者
每个 shared_ptr 都有一个关联的计数器,通常称其为引用计数。
无论何时拷贝一个 shared_ptr ,计数器都会增加。
当给 shared_ptr 赋予一个新值或是 shared_ptr 被销毁时,计数器就会递减。
一旦一个 shared_ptr 的计数器变为0,它就会自动释放自己所管理的对象:
auto r = make_shared<int>(42); // r指向的 int 只有一个引用者
r = q; // 给 r 赋值,令它执行另一个地址
// 递增q指向的对象的引用计数
// 递减r原来指向的对象的引用计数
// r 原来指向的对象已没有引用者,会自动释放
shared_ptr 自动销毁所管理的对象……
当指向一个对象的最后一个 shared_ptr 被销毁时,shared_ptr 类会自动销毁此对象。
它通过另一个特殊的成员函数——析构函数完成销毁工作。
析构函数一般用来释放对象所分配的资源。
shared_ptr 的析构函数会递减它所指向的对象的引用计数。如果引用计数变为0,shared_ptr 的析构函数就会销毁对象,并释放它占用的内存。
…… shared_ptr 还会自动释放相关联的内存
当动态对象不再被使用时,shared_ptr 类会自动释放动态对象,这一特性使得动态内存的使用变得非常容易。
使用了动态生存期的资