Effective C++:资源管理

资源:动态分配的内存、文件描述器、互斥锁、图形界面中的字型与笔刷、数据库连接以及网络sockets等,无论哪一种资源,重要的是,当你不再使用它时,必须将它还给系统。

条款13:以对象管理资源

当我们向系统申请资源后,一定要记得释放,不然就容易发生内存泄漏。但是意识到这样一件事并不是很容易,比如我们是通过一个函数来动态分配内存并返回一个指针。

Investment* ceateInvestment();// 返回指针,指向动态分配对象
void f()
{
Investment* pInv = ceateInvestment();
// ...
delete pInv;
}

即使像上面的代码一样,我们在用完指针pInv后,我们调用了delete,但是还是可能出问题,有时候我们可能在...的部分提前return或跳出了循环,甚至在该部分发生了异常,这都导致delete根本执行不到。

解决方法是我们把指针放在一个资源管理的类里,让类对象在生命结束的时候,会自动调用析构函数,而析构函数里会执行delete。

两个常被使用的RAII类分别是:shared_ptr和unique_ptr,它们间不同的是shared_ptr允许存在同一内存区域的多个指针拷贝,而unique_ptr只允许一份指针指向对象,当uniuqe_ptr发生赋值操作时,用于赋值的指针将会变成null。

条款14:在资源管理类中小心copying行为

在实际管理资源时,并非所有的资源都是堆内存(heap),所以unique_ptr或shared_ptr这样的智能指针往往不适合作为资源管理者。

比如你需要控制类型为Mtux的互斥器对象,共有lock和unlock两函数可用,你需要保证的就是不要忘记将一个被锁住的Mutex解锁,我们的想法的主旨就是:资源在构造期间创建,在析构期间释放。

class Lock
{
public:
explicit Lock(Mutex* pm) :mutexPtr(pm){ lock(mutexPtr;) }// 获得资源
~Lock(){ unlock(mutexPtr); }// 释放资源
};

这样虽然很好,但是如果Lock被复制了,就会发生问题。它可能会引起对了一Mutex解锁两次。

常见的解决方案有2种:一种是禁止复制;第二种是对底层资源祭出“引用计数法”,这也是shared_ptr实现原理。

条款15:在资源管理类中提供对原始资源的访问

很多API接口往往要求访问原始资源,所以每一个RAII class应该提供一个“取得其所管理之资源”的办法,比如提供一个get函数。

对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,但隐式转换对客户比较方便。

条款16:成对使用new和delete时要采用相同形式

如果你在new表达式中使用[],必须在相应的delete表达式中使用[]。如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[]。

string* stringPtr1 = new string;
string* stringPtr2 = new string[100];
delete stringPtr1; // 删除一个对象
delete[] stringPtr2; // 删除一个由对象组成的数组

条款17:以独立语句将newed对象置入智能指针

假设我们有个函数用来控制程序的优先权,另一个函数用来在某个动态分配所得到的Wieget上进行某些带有优先权的处理:

int priority();
void processWidget(shared_ptr<Widget>pw, int priority);

现在假如我们这样调用它:

processWidget(share_ptr<Widget>(new Widget),priotrity());

在调用processWidget之前,编译器必须创建代码,做以下三件事:

  • 调用priority

  • 执行”new Widget”

  • 调用shared_ptr构造函数

C++编译器并不保证上次代码执行的次序,但有一点可以保证,那就是new Widget肯定发生成share_ptr构造函数之前。

假如priority发生在第二步,并且执行过程中发生了异常,那就有可能资源不能正常的释放。

避免这种情况,就需要使用分离语句,先创建Widget,然后再将它置入一个智能指针内,然后再把那个智能指针传给processWidget。

Effective C++:资源管理,布布扣,bubuko.com

时间: 2024-10-11 12:10:50

Effective C++:资源管理的相关文章

Effective C++ —— 资源管理(三)

条款13 : 以对象管理资源 假设有如下代码: Investment* createInvestment(); //返回指针,指向Investment继承体系内的动态分配对象,调用者有责任删除它 void func() { Investment* pInv = createInvestment(); //调用factory函数 ..... delete pInv; //释放pInv所指对象 } 上述代码可能出现如下问题导致无法删除pInv指针所指对象,出现资源泄露. (1)“.....”区域内一

Effective C++ -- 资源管理

13.以对象管理资源 void f() { Investment* pInv = createInvestment(); ... delete pInv; } 以上代码存在问题:在delete之前出现异常,导致pInv无法删除,造成资源泄露. 解决方法:RAII Resource Acquisition Is Initialization 资源获取时机即初始化 使用智能指针,代码如下: void f() { auto_ptr<Investment> pInv(createInvestment(

c++内存管理学习纲要

本系列文章,主要是学习c++内存管理这一块的学习笔记. 时间:6.7-21 之下以技术内幕的开头语,带入到学习C++内存管理的技术中吧: 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,因此要想成为C++高手,内存管理一关是必须要过的! 笔记汇总: 1.C++内存管理学习笔记(1) 2.C++内存管理学习笔记(2) 3.C++内存管理学习笔记(3) 4.C++内存管理学习笔记(4) 5.C++内存管理学习笔记(5) 6.C++内存管理学习笔记(6) 7.C++内存管理学习笔记(7

Effective C++:条款14:在资源管理类中小copying行为

(一) 上一条款说的auto_ptr和tr1::share_ptr适合于heap-based的资源,然而并不是所有资源都是heap-based的.换句话说并不是tr1::shared_ptr 和 auto_ptr 永远适合做为资源的管理者.所以有时难免还是需要实现自己的资源管理类型. 假设Mutex类型通过lock和unlock两组函数进行互斥器的锁定和解锁,可能我们希望和auto_ptr一样的行为,在某个智能类型析构时主动调用unlock进行解锁.比如下面的代码: void lock(Mute

《Effective C++》 读书笔记之三 资源管理

<Effective C++> 读书笔记之三 资源管理 准备知识: 所谓资源就是,一旦用了它,将来必须还给系统.最常用的资源是动态分配内存,其他常见的资源有文件描述器.互斥锁.图形界面的字形和笔刷.数据库连接以及网络sockets. auto_ptr 是个"类指针对象",就是所谓的智能指针,其析构函数自动对其所指对象调用delete.auto_ptr位于 #include <memory> 头文件.由于auto_ptr被销毁时会自动删除它所指之物,所以一定要注意

【effective c++】资源管理

以对象管理资源的观念常被称为“资源取得时机便是初始化时机”(RAII) auto_ptr被销毁时会自动删除它所指之物,所以一定要注意别让多个auto_ptr同时指向同一对象,否则对象会被删除多次,行为未定义 auto_ptr有一个性质:若通过拷贝构造函数或拷贝构造运算符复制它们,它们会变成NULL,而复制所得的指针将取得资源的唯一拥有权 class Investment { private: double value; public: Investment(double val):value(v

Effective C++ 条款13/14 以对象管理资源 || 在资源管理类中小心拷贝行为

三.资源管理       资源就是一旦你使用了它,将来不用的时候必须归还系统.C++中最常用的资源就是动态内存分配.其实,资源还有 文件描述符.互斥器.图形界面中的字形.画刷.数据库连接.socket等. 1.        以对象管理资源       void f() {     investment *plv = createInvestment();     //这里存在很多不定因素,可能造成下面语句无法执行,这就存在资源泄露的可能.     delete plv; }      这里我们

Effective C++:条款15:在资源管理类提供对原始资源的访问

(一) 下面代码: tr1::shared_ptr<Investment> pInv(createInvestment()); int daysHeld(const Investment* pi); 我们要调用daysHeld函数的话,就必须传递一个Investment指针,但是我们现在只有pInv对象,所以我们需要一个函数可将RAII class(本例为tr1::shared_ptr)对象转换为其所内含之原始资源(本例). 有两种方法,一种是显式转换,另外一种是隐式转换. (二)显式转换 t

Effective C++ 条款15、16 在资源管理类中提供对原始资源的访问||成对使用new 与 delete要采取相同形式

1.在资源管理类中提供对原始资源的访问     前几个条款很棒,它们是对抗资源泄露的壁垒,但很多APIs直接指向 资源,这个时候,我们需要直接访问原始资源.     这里,有两种方法解决上述问题,我们可将RAII对象转换为原始资源.通过 显式转换与隐式转换.     通常,tr1:: shared_ptr 和 auto_ptr 都提供一个get成员函数,用来执行显式转换,也就是返回智能指针内部的原始指针的复件.因为它也重载了指针取值操作符* –>.当然也可以通过隐式转换为底部原始指针.