第十二章 动态内存
动态-dynamic,一般在C/C++里指的是程序运行过程中产生的、经常改变的
相对于静态对象而言,动态对象的生存周期编译器不能确定,由写程序的人主动管理,即创建、使用、销毁应当由程序员手动完成
从大量实践来看,动态对象的释放是最容易出错的地方,具体到C++里就是指针这种使用堆空间的对象什么时候释放以及如何释放的问题
12.1 new - delete --> 智能指针
大学编程语言学C++的一定都学过new和delete,这是C++从C语言中的malloc和free进化而来的直接管理内存的方法
新标准觉得这样还是太容易出问题,导致悬垂指针、空指针等,于是继续封装产生了三个智能指针
定义在<memory>头文件
shared_ptr
std::shared_ptr - cppreference.com
由于shared_ptr类允许多个指针指向同一个对象,所以内部实现不可避免会有一个计数器
最安全的是使用make_shared创建shared_ptr对象:
new & delete
new出来的对象被默认初始化:内置类型未定义,对象用默认构造函数
如果堆不够大,则new抛出bad_alloc异常,或者使用placement new(见19章)
delete只能用于new出来的且非空指针,否则都是UB
还要注意空悬指针的问题
- 练习12.6
好像没用到delete... - 练习12.9
new & shared_ptr
get()可以返回底层指针,但是要确保指针不被释放,因此不建议使用get初始化智能指针
- 练习12.10
函数的参数和p指向同一块内存,但由于参数是智能指针所以引用计数会+1,不会有释放两次的情况,调用正确 - 练习12.11
用p的底层指针初始化智能指针会导致函数运行完参数被销毁,p指向的内存也被释放,那p就失去了意义,p再被销毁时就会出现同一片内存释放两次的bug
启示:智能指针和普通指针不要混用 - 练习12.12
process是个接受shared_ptr拷贝的函数
(c)非法,普通指针转智能指针是explicit转换构造不允许隐式转换
(d)会导致p变成空悬指针 - 练习12.13
windows上的mingw还是不如Linux环境,Linux有异常会报出来并显示aborted
异常相关
可以自己写智能指针的析构操作(函数对象)
默认都是delete,但delete肯定不会满足所有类的需求,因此还需要注意资源释放的操作
unique_ptr
注意unique_ptr只支持直接初始化,不允许赋值和拷贝(将要被销毁的可以,如函数返回值)
书上说没有返回unique_ptr的标准库函数,但实际上C++14版本已经有make_unique用来构造unique_ptr
std::unique_ptr - cppreference.com
release返回值要利用起来,用来转移所有权
unique_ptr的销毁操作是模板参数,这点和shared_ptr作为构造函数参数不一样
- 练习12.16
weak_ptr
指向shared_ptr管理的对象,但不控制对象生存期
搜了一下weak_ptr的设计主要是解决shared_ptr导致的循环引用死锁,将其中一个改用weak_ptr就可以解决
理解应该是将weak_ptr看成房地产中介,对房子没有所有权但可以访问
这个工具还可以用到观察者这一设计模式中,需要多用才能体会
12.2 动态数组
这里指的不是vector,而是new一个数组
new和delete加上中括号[]即可
allocator类
这里提到一个将分配存储空间和初始化分离的类叫做allocator,这个技术可以了解一下
后面的程序就不看了,是一个综合应用
第十二章结束~