effective C++读书笔记(三)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

3. 资源管理(Resource Management)

从条款13到条款17都在讲资源管理,那么什么是资源呢?我觉得,资源就是诸如new出来的东西(堆内存),互斥锁啊,数据库的链接等等,操作这些东西要特别小心,因为用了就没有了,比如堆内存,你new了不释放,迟早就是bad_alloc,比如锁,你占了不释放,别人一辈子也得不到。

 

C++的常见资源有动态分配内存、文件描述器、互斥锁、图形界面下的字符和笔刷、数据库连接以及网络的 sockets。不论哪一种资源,当不再使用时,应该将它还给系统。

条款13: 以对象管理资源(useobjects to manage resources)

本条款建议程序员使用对象管理资源(如申请的内存),核心思想就是:把资源放到类里面,将资源释放的活放在类的析构函数中。我们利用的思想就是类的析构函数在对象的生命周期结束,或者有异常的时候自动调用,因此,我们不用担心造成资源的泄露。并且,由条款08知道,析构函数绝不抛异常,因此我们可以放心使用

书上一句经典的话:获得资源后立即放进资源管理对象,我们总是在获得一笔资源后于同一语句内以它初始化某个管理对象。因此资源取得时便是资源管理对象初始化的时候

给出的经验是:

1为防止资源泄漏(常常是由于程序员忘记delete申请的内存,或是由于程序过早的returncontinuegoto语句等等导致),请使用RAII资源取得时机便是初始化时机Resource Acquisition Is Initialization)对象,它们在构造函数中获得资源并在析构函数中释放资源。例如使用类指针对象”auto_ptr

void f(){
 std::auto_ptr<investment> pInv(createInvesment());
 ....        //auto_ptr的析构函数会自动删除pInv
}

2)两个常被使用的RAII classes 分别是:auto_ptrtrl::shared_ptr引用计数型智慧指针reference-counting smart pointerRCSP)。为了防止多个auto_ptr指向同一对象时,对象可能会被删除一次以上而导致错误,auto_ptr复制动作会使它(被复制物)指向null

std::auto_ptr<Investment>pInv1(createInvestment()); //pInv1指向createInvestment()返回物;
     std::
auto_ptr<Investment> pInv2(pInv1);                    //现在pInv2指向对象,而pInv1被设为NULL;
     pInv1 = pInv2;                                                           //
现在pInv1指向对象,而pIn2被设为NULL;

RCSP则持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。因此,trl::shared_ptrcopy行为更加直观一些。这两个智能指针都不能用于数组,因为,他们的析构函数调用的是delete而不是delete[](他们觉得,vectorstring已经足够了,没有必要再用数组)。可以看看boost的智能指针,那儿有对数组需求的支持

 

条款14: 在资源管理类中小心 copying 行为(Thinkcarefully about copying behavior in resource-managing classes)

本条款提醒程序员,使用资源管理类时需根据实际需要管理copying行为,常见的有:抑制copying(将copying操作声明为private);施行引用计数法(使用智能指针:trl::shared_ptr,当引用次数为0时,自动调用删除器);深度拷贝(复制指针和所指内存);转移底部资源的拥有权(将资源的拥有权从被复制物转移到目标物,例如auto_ptr)。

1、禁止复制(比如锁啊,数据库的链接啊,这种),实现的方式就是条款6讲的,将copying函数作为private或者继承Uncopyable类

2、底层采用 “引用计数”,及tr1::shared_ptr这种方法,就是说,资源记者又几个对象指着它,直到最后一个对象死了就释放资源

3、复制底层资源:深度赋值,不光复制指针,还复制指针指着的东西

4、转移资源的拥有权:就是一旦被copying,自己就失去了资源,例如auto_ptr这种。

 

条款15: 在资源管理类中提供对原始资源的访问(Provideaccess to raw resources in resource-managing classes)

1 APIs往往要求访问原始资源(raw resources) ,所以每一个RAII class 应该提供一个取得其所管理之资源的办法。

2)对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换(如调用get()成员函数)比较安全,但隐式转换对客户比较方便。

   tr1::shared_ptrauto_ptr都提供一个get成员函数,用来执行显示转换,也就是返回智能指针内部的原始指针(的复件)。就像所有智能指针一样, tr1::shared_ptrauto_ptr也重载了指针取值操作符(operator->operator*),它们允许隐式转换至底部原始指针。(即在对智能指针对象实施->*操作时,实际被转换为被封装的资源的指针。)

 

条款16: 成对使用new delete 时要采取相同形式(Usethe same form in corresponding uses of new and delete)

本条款提醒程序员在申请和释放资源时应采用相同形式:如果在new 表达式中使用[],必须在相应的delete表达式中也使用[];如果你在new 表达式中不使用[],一定不要在相应的delete表达式中使用[]

new被调用时,首先分配内存,再针对此内存会有一个(或更多)构造函数;当delete被调用时,针对此内存会有一个(或更多)析构函数被调用,再释放内存。由于delete必须知道即将被删除的内存内究竟存在多少个对象,从而决定调用多少个析构函数,所以采用相同形式很重要。

   最好尽量不要对数组形式作typedefs动作。因为这样容易引起delete操作的疑惑

 

条款17: 以独立语句将newed 对象置入智能指针(Storenewed objects in smart pointers in standalone statements)

本条款涉及C++对语句的执行次序,如果次序不能确定,最好写成独立的语句。以智能指针为例,给出的建议是:以独立语句将newed 对象存储于(置入)智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。假设:

processWidget(std::trl::shared ptr<Widget> (new Widget) , priority());

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

1)执行“new Widget”

2)调用priority

3)调用trl::shared ptr构造函数

不同的C++ 编译器执行这三条语句的顺序不一样,但对priority的调用可以排在第一或第二或第三执行。如果编译器选择以第二顺位执行且priority函数抛出了异常,则新创建的对象Widget将导致内存泄漏。解决方法如下:

std::trl::shared_ptr<Widget> pw(new Widget);  //在独立语句内以智能指针存储Widget对象
processWidget(pw, priority());   //这个调用肯定不存在内存泄漏

 

这一章的核心思想:用类去管理资源,然后,我们只要按规矩(这个规矩已经系统化,成熟化)去写好我们的资源管理类(核心就是copying函数)。

Effective C++ | 读书笔记 提前定义变量,有可能导致变量并没有使用(如中间抛异常了),而平白多了一个构造和析构成本。但是循环怎么办?// 方式AWidget w;i < n;...// 方式Bi < n;++i) {...做法A:1个构造 + 1个析构 + n个赋值操作做法B:n个构造函数 + n个析构函数打破本条款选择A的依据:(1)你知道赋值成本比“构造+析构"成本低。(2)你正在处理代码中效率高度敏感的部分。否则你应该使用做法B,维持变量尽可能在使用时定义的原则。请记住。 阅读详情

相关推荐

Effective C++ 读书笔记

条款8:别让异常逃离析构函数 在定义本类时出现的异常,应该在析构函数中捕获或者在析构函数中考虑在出现异常时强制结束程序。如果想要针对异常作出相应,可以考虑将出现异常的代码块放到一个普通函数中。 条款9:绝不在构造和析构过程中调用virtual函数 由于virtual函数的机制是动态绑定,根据实际的对象确定要调用的是基类还是子类的函数,此时需要知道的是对象已经存在,即构造函数是确定的,所以,构造函数不可以声明为virtual的。同理,析构过程中也不可以调用virtual函数,因为析构后的对象不复存在,所

如沐清风的博客 181

Effective C++读书笔记

一.实现 26.尽可能延后变量定义式出现的时间: a)      只有真的要用这个变量了,才进行定义。防止不必要的定义造成浪费。     b)      如果可以通过copy构造函数构造就能省去对象默认构造并赋值的浪费。 c)      关于循环内使用一个对象,定义在循环外还是循环内的问题,这个本人纠结了好久。现在终于有相对明确的答案了: 定义在循环外需要:1个构造函数,1个析构函数,

puppet_master的专栏 698

Effective C++ 读书笔记

设计一个time的基类和多种计时方法,许多客户只想使用时间,不关系如何实现时间的细节,我们可以设置一个factor函数根据factor的规则,geTimeKeeper返回的对象必须位于堆区,因此为了避免内存泄漏,我们需要对其进行释放;然而纵使客户把每一件事都做对了,仍然无法知道程序如何行动。问题出在返回的指针指向派生类对象,但那个对象却被基类指针delete,而目前的基类析构函数是非虚函数。

qq_53660404的博客 808

Effective c++读书笔记

.资源管理 所谓资源就是,一旦用了它,将来必须还给系统。C++程序中最常使用的资源就好似动态分配内存(如果你new了,却忘了delete,会导致内存泄露),但内存只是你必须管理的众多资源之一。其它常见的有文件描述符(file descriptors)、互斥器(mutex)、图形界面中的字形和画刷。数据库连接以及网络sockets。当你不使用它们时,记得还给系统。 当你考虑到异常、函数内多重回

小李的专栏 484

Effective C++ 读书笔记 条款一至

条款一 视C++为一个语言联邦记住,C++中的四种次语言.. 1.C. c基础..2.Object-Oriented C++ ,c++的主要,class ,类封装,继承,多态等.3.Template C++ ..c++里头的泛型编程..模板编程.4.STL.  标准模板库..如vector,queue,map等.这个条款所叙述的..应当在次语言变换时候,高效

风一样消逝的青春 693

Effective C++ 读书笔记()

 Effective C++ 读书笔记()记住一句很重要的话:如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果两边都出现,表示被指物和指针两者都是常量.Mutable:C++中的一个于const相关的摆动场,可变的,它可以释放掉non-static成员变量的btiwise constness约束. 

331

More Effective C++ 读书笔记

条款8:了解各种不同意义的new和delete 这里讲了3种new,分别是:new operator, operator new, placement new。 new operator最简单,它就是我们平时常用的new关键字,需要注意的是,它是不能被重载的。new operator的语义是先分配内存,然后调用对象的构造函数。 operator new:...

weixin_34194317的博客 122

effective c++读书笔记()

资源管理

VanityLost_CY的博客 278

effective C++读书笔记

23.编译器查找某个函数或变量的过程: 假设这个函数是某个派生类的成员函数 local作用域(函数内)->该派生类的作用域->该派生类基类的作用域->内含基类的namespace作用域->global作用域。 参考:《effective c++》p157   24.派生类内的名称会遮掩基类的名称(比如基类内有若干重载成员函数飞f(),派生类内又实现了自己的重载版本,那么public继承并

projectoflion123的专栏 362

effective c++读书笔记

条款18 让接口容易被正确使用,不易被误用 tr1::shared_ptr缺省删除器来自“tr1::shared_ptr”诞生所在的dll std::tr1::shared_ptr createInvestment() { std::tr1::shared_ptr reVal(static_cast (0),getRidofInvestment);//指定删除器 reVal = ...

chenbainian的专栏 543

effective C++ 读书笔记

章资源管理 条款13:以对象管理资源 RAAI(Resource Acquisition IsInitialization: RAII) 资源取得时机便是初始化时机 n        为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源 n        两个常被使用的RAIIclasses分别是tr1::shared_ptr和auto_ptr。前者通常是

kindlucy的专栏 973

C++ 读书笔记 Effective C++(

public继承意味着is-a;virtual函数意味着接口必须被继承 none-virtual函数意味着接口和实现都必须被继承。 32.确定你的public继承塑模出is-a关系        “public继承”意味is-a.适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived class对象

zzbjut 2272

More Effective C++读书笔记

异常 条款9:使用析构函数防止资源泄漏 这一章我觉得可以算作是异常安全处理的一种情况,也就是说在异常发生的情况下,保证资源能被正确释放。 这里分为两种情况来讨论, 一是指针操作 举个例子: void myFucntion()  {      Object* obj= getBack();      obj->doSomething();      delete obj; 

necrazy的专栏 974

effective C++读书笔记()尽量使用const

ddvdss

zxy2011qp的专栏 910

effective C++读书笔记 条款 尽可能使用const

const允许你指定一个语义约束,告诉编译器不改动某个对象 关于指针的const,如果const出现在*左边,表示被指物是常量,如果出现在*右边,则表示指针是常量,如果两边都有,则表示指针和被指物都是常量。 void f1(const int* a); //f1获得一个指针,指向一个常量 void f2(int const * a); //f2也是 void f3(int* const a)

csd_ncl_oud的博客 320
上一篇: effective C++读书笔记(二)
下一篇: effective C++读书笔记(四)
necrazy
博客等级 码龄18年 27粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值