《Effective C++》阅读总结(三):资源管理
- 2022 年 5 月 29 日
- 笔记
- C++, EffectiveC++, 学习
C++中的资源管理非常重要,在将资源加载到内存后,便可以使用资源了,当我们不再需要资源时,我们要保证其正确的释放,才能将其占用的内存空间归还给操作系统,不正确的释放很容易造成内存泄漏。本章以资源管理类为基础,提出了以下几条准则,这章内容比较简单,大概总结一下:
13. 以对象管理资源
绝大多数资源都是动态分配于堆内存之中,然后被用于某个局部范围区域内。这类资源应该在控制流离开该区域时被释放,或者全局资源在退出main函数时也应该释放。通常我们用new创建一个堆对象,最在使用完对象后用delete完成销毁释放,在创建后销毁前期间,如果发生函数提前退出或者对象指针被重置,则相应的堆内存就无法释放了。智能指针是一种指针管理类,它可以执行几乎所有裸指针能执行的操作,而且智能指针在离开作用域时会自动调用所指对象的析构函数,所以用智能指针对象来管理资源的指针是一个非常好的选择。一个很简明的原则就是:资源获取时便进行初始化————RAII。即一个获取的资源在获得时就应该被放进资源管理类(智能指针)中,并在资源管理类析构的时候完成资源释放。例如:std::shared_ptr<OneClass> p_oneclass(new OneClass(666))
,这种写法能够保证在适当的时候正确释放对象。
PS:当然,无脑使用智能指针也不好,在调试代码的时候,无法直接看到智能指针所指对象的成员状态,不利于修bug。
14. 在资源管理类中小心copy行为
如果需要复制RAII对象,那么也请完全复制其管理的资源,但资源我们一般都是读取,所以更好的选择是抑制copy行为,在copy时实施引用计数,当引用计数为0时,执行析构释放资源。总之就是使用std::shared_ptr管理对象。
15. 在资源管理类中提供对原始资源的访问
这是为了适配需要访问原始资源的接口,所以智能指针提供了一个.get()
接口返回其管理的裸指针。但需要明确的是,获取的裸指针只用来访问资源,不应对该指针执行delete,因为释放操作是授权给智能指针的。多次释放会导致非法释放内存错误。
16. 成对的使用new和delete时,要采用相同的形式
这个很简单,即构造一个对象,调用new
构造,调用delete
释放。构造对象数组,调用new Array[]
构造,调用delete[] Array
释放。
17. 以独立语句将newed对象置入智能指针
① 智能指针的构造函数是explicit的,即不会对输入参数进行隐式转换;
还是为了防止内存泄漏,以独立语句将newed对象置入智能指针,即std::shared_ptr<OneClass> p_oneclass(new OneClass(666))
单独一行。因为如果这样使用int ret = Fun(std::shared_ptr<OneClass>(new OneClass(666)), other_func())
, 编译器有可能将other_func()
的执行放在new完对象和构造智能指针对象之间,如果此时other_func()
抛出异常,那么指向资源的指针会丢失,造成内存泄漏。
小结:将你不知道该何时释放的对象放入智能指针管理。