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

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

                                                                                                                                By Ryui Liu 2011/11/28

所谓资源就是一旦用了它,将来必须还给系统,如果不这样,糟糕的事情就会发送,如内存泄漏等等,c++中最常使用的资源就是动态内存,但内存只是必须管理的资源之一,其他常见资源如文件描述器(file descriptors)、互斥锁、图形界面中的字型和笔刷、数据库连接以及网络sockets等等。不论那种资源,当你不使用它时,必须将它还给系统。

一、以对象管理资源:

    假设我们有一个root class.

      Class Investment{.....};

然后通过一个工场函数供应特定的Investment继承体系内的对象。

      Investment * createInvestment();

一般情况下我们使用方法都是

      Investment *pInv = createInvestment();

      .....

      delete pInv;

这样看起来毫无问题,但是当有人需要变更程序,在“...”处加入流控制,如return 语句、goto语句,此时就可能导致跑不到delete pInv语句。

为确保createInvestment返回的资源总是被释放,我们就需要把资源放进管理对象内,这些对象的析构函数会自动释放那些资源。

std::auto_ptr<Investment> pInv(createInvestment()); //调用factory函数 创建管理对象pInv

auto_ptr是“类指针对象”,也就是所谓的智能指针,其析构函数自动对其所指对象调用delete

到此为止,可以总结“以对象管理资源”的关键:

1、获得资源后立刻放进管理对象(managing object)内:以上代码中createInvestment返回的资源被当作其管理者auto_ptr的初值。“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(Resource Acquisition is Initiali RAII,资源管理对象也称为RAII对象  

2、管理对象运用析构函数确保资源被释放:不论控制流如何离开区块,一旦对象被销毁,其析构函数自然会被自动调用,于是资源被释放。

   但是auto_ptr有个特性:受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向他。因此在调用copy构造函数或copy assignment操作符复制它们的时候,原管理器会变成null,而复制所得的指针将取得资源的唯一管理权。在STL中要求其元素有正常的复制行为,因此这些容器容不得auto_ptr,由此可见auto_ptr并非管理资源的神兵利器。

Std::auto_ptr<Investment> pInv1(pInv);//此时pInv被设为null;

pInv = pInv1; //此时pInv1被设为null;   

auto_ptr的替代方案是“引用计数型智慧指针(reference-counting smart pointer: RCSP)”。RCSP将持续追踪有多少个对象指向某资源,当无人指向它是会自动删除该资源。TR1tr1::share_ptr就是个RCSP,其复制行为比较正常。

二、资源管理类中copying行为:

    下面有一个类对类型为Mutex的互斥对象进行管理

Class Lock{

  Public: 

     explicit Lock(Mutex *pm):mutexptr(pm)

     {  lock(mutexPtr);}

     ~Lock(){ unlock(mutexPtr)}

  Private:

     Mutex * mutexPtr;  

}

此时调用构造函数时会锁定互斥器,在区块末尾时,自动接触互斥器锁定。

但是当Lock对象被复制时:Lock m11(&m);  Lock ml2(ml1); 这时会怎么样?

“当一个RAII对象被复制时,会发生什么?”,我们有如下两种选择

1、禁止复制: 当允许RAII对象被复制时并不合理,此时需要禁止复制,即将coping操作声明为私有。

2、对底层资源使用“引用计数法”:

上面的示例中就可以将Mutex* 变为std::tr1::shared_ptr<Mutex> mutexPtr; 并将tr1::shared_ptr的“删除器”指定为unlock函数,这样在引用计数为0时,解除锁定,而不是删除对象。构造函数改为:

 explicit Lock(Mutex *pm): mutexPtr(pm,unlock) { lock(mutexPtr.get());}

3、复制底部资源:当希望一份资源可以有任意数量的复件时,可以复制底部资源。例如某些标准字符串类型是由“指向heap内存”的指针构成。这种字符串对象还含有指针指向的一块heap内存,当这样的字符串被复制时,不论指针还是指针指向的内存都会被制作出一个复件。

4、转移底部资源的拥有权auto_ptr 就是这么处理的。

   三、在资源管理类中提供对原始资源的访问:

   有时候需要绕过资源管理器对象直接访问原始资源,例如一个函数int daysHeldconst Investment *pi)需要直接访问Investment指针,而现在只有tr1::share_ptr<Investment>的对象。这时候就需要一个函数将RAII class对象转换为其所包含的原始资源。

1、显式转换: tr1::shared_ptrauto_ptr都提供了一个get成员函数,用来显示转换,他返回智能指针内部的原始指针(的附件)。 Int daysHeld(pInv.get());

2、隐式转换: 如果需要用原始指针的函数,智能指针可以直接通过操作符->*进行引用,因为智能指针重载了取值操作符,运行隐式转换为底部原始指针。这里的隐式转换是从类类型转换为成员变量类型,不同于无explicit声明的单参数构造函数将成员变量类型转换为类类型

示例:FontHandle getFont();

      FontHandle releaseFont();

 资源管理类

      class Font{

         public:

           //C++中单参数构造函数若不声明为explict,

           //在合适的场合可以产生隐式转换:由成员变量类型转换为类类型。 

           explicit Font(FontHandle fh):f(fh){}

           ~Font(){releaseFont(f);}

           FontHandle get()const {return f;}//显示转换函数

           //可以提供一个隐式转换函数,由类类型转换为成员变量类型

           Operator FontHandle()const{ return f;}

         Private:

            FontHandle f;

      }

四、以独立语句将new操作符创建的对象置入智能指针,如果不这么做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。例如:

       int priority();

       void processWidget(std::trl::shared_ptr<widget> pw, int priority);

调用上面函数时:

        processWidget(std::trl::shared_ptr<widget>(new Wigdet), priority());

上面的调用看似不会出现内存泄漏,实则不然:C++编译器调用之前必须先处理实参,由于c++编译器的不确定性,可能产生的操作顺序为:

        1、执行"new Widget" 2、调用 priority 3、调用 trl::shared_ptr构造函数。

假如上述过程第2步产生异常,此时"new Widget"返回的指针将会遗失,因此可能导致资源泄漏。解决这类问题的办法即是:以独立语句将new操作符创建的对象置入智能指针.上述调用过程分拆为:

          std::trl::shared_ptr<widget>  pw(new  Widget);

          processWidget(pw, priority());    

    五、成对使用newdelete时要采用相同形式:即当你在new表达式中使用[],必须在相应的delete表达式中也使用[],如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[]

Effective C++读书笔记(详细总结55条款)上篇 下面从四个方面来说 (1) C++ 以 C 为基础,很多语句语法都没有改变,只是进行了扩展,C++ 解决问题的时候,可以理解为 C 的高效解法 (2) 面向对象,有构造函数,析构函数,继承、封装、多态、虚函数动态绑定,这是不同于C 语言的部分 (3) 泛型编程、可以理解为代码的模型,但是代码本身并不占用内存空间,只有在实例化的时候,才分配内存,所以可以提高代码复用性 阅读详情

相关推荐

Effective C++读书笔记

 记得前段时间又一次拿起《Effective C++》的时候,有种豁然开朗的感觉,所以翻出了我第一遍读时做的笔记。只做参考以及查阅之用。如有需要请参阅《Effective C++》书本。 by shenzi/2010.5.17一.让自己习惯C++   条款01:视C++为一个语言联邦    为了更好的理解C++,我们将C++分解为四个主要次语言:C。说到底C++仍是以C

shenzi的天空 2万+

Effective C++_读书笔记

设计与声明。

Mr.Andy的博客 1450

Effective C++读书笔记(上)

Effective C++读书笔记(一到三章)

still_wtm的博客 745

C++】《Effective C++读书笔记汇总

我之前边读《Effective C++》边写下每个条款的读书笔记,这一版是C++11之前的版本。这里我将每个条款令我印象深刻的点小结一下。 1、C++包括:Plain C(面向过程)、OOP(面向对象)、模板(泛型和模板元编程)、STL(C++标准库)。 2、用inline、enum、const代替#define。#define定义的宏,一旦复杂起来,高手都很难掌控。不要带入C的习惯。

artzers的专栏 6062

Effective C++

可增加程序的清晰度并改善程序效率class Apublic:public://绝不class Apublic:public://绝不编写类模板,而它提供于此模板相关的函数支持所有参数隐式转换时,需要为这个类模板增加内部friend函数public://增加friend + 声明 + 定义private:T re, im;

weixin_44332995的博客 997

Effective C++读书笔记(一)

Effective C++读书笔记 条款01:视C++为一个语言联邦 C++高效编程守则视状况而变化,取决于你使用C++的哪一部分(C, Obejct-Oriented C++, Template C++, STL)。 条款02:尽量以const, enum, inline替换#define 对于单纯常量,最好以const对象或enum替换#define。 对于形似函数的宏,最好改用inline函数代替#define。 条款03:尽可能使用const 将某些东西声明为const可帮助

WINGREZ‘S BLOG 605

Effective C++ | 读书笔记 (二)

第三版第三四章内容

m0_74795952的博客 1075

effective c++读书笔记

effective c++读书笔记一级目录二级目录三级目录Charpter 1. 让自己习惯C++条款01: 视C++为一个语言联邦条款02: 尽量以const,enum,inline替换#define条款03: 尽可能使用const条款04: 确定对象被使用前已先被初始化Charpter 2. 构造/析构/赋值运算条款05: 了解C++默默编写并调用哪些函数条款06: 若不想使用编译器自动生成的函数,就该明确拒绝条款07: 为多态基类声明virtual析构函数条款08: 别让异常逃离析构函数条款09: 绝

cwdben的博客 545

Effective C++读书笔记(持续更新)

protected:private:​// 为阻止HomeForSale对象被拷贝,需要继承Uncopybale​。

XT3121000506的博客 1641

Effective C++读书笔记

Effective C++》的目录方便回顾。 1.视c为一个语言联邦 2.尽量以constenuminline替换-define 3.尽可能使用const 4.确认对象被使用前已先被初始化 5.了解c默默编写并调用了哪些函数 6.若不想使用编译器自动生成的函数就该明确拒绝 7.为多态基类声明virtual析构函数 8.别让异常逃离析构函数 9.绝不在构造和析构过程中调用virtual函数 10.令operator-返回一个reference-to-this 11.在operator-中处理自我赋值 12.

江城的博客 413

EFFECTIVE-C++读书笔记

EFFECTIVE-C++读书笔记

qq_35547417的博客 812

Effective cpp 读书笔记3

资源管理 13.以对象管理资源 14. 在资源管理类中小心copying行为 15.在资源管理类中提供对原始资源的访问 16.成对使用new和delete时要采用相同形式 17.以独立语句将newed对象置入智能指针

GZGlenn的博客 541

effective C++读书笔记

effective C++读书笔记

frankwyw的博客 706

Effective C++ 读书笔记总结

Effective C++ 读书笔记总结 一 、 书本目录 让自己习惯C++ 条款01:视C++为一个语言联邦 条款02:尽量以const,enums,inline替换#define 条款03:尽可能使用const 条款04:确定对象被使用前先被初始化 构造/析构/赋值运算 条款05:了解C++默默编写并调用哪些函数 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 条款07:为多...

qq_40028201的博客 388

Effective C++ 读书笔记

1、让自己习惯C++ Accusoming Yourself to C++  条款01:视C++为一个语言联邦  条款02:尽量以const,enum,inline 替换 #define  条款03:尽可能使用const  条款04:确定对象被使用前先被初始化 2、构造/析构/赋值运算 Constructors,Destructors,and Assignment Operators  条款05:了解 C++ 默默编写并调用哪些函数  条款06:若不想使用编译器自动生成的函数,就该明确拒绝  条款07:为多

weixin_45867382的博客 197

读书笔记-Effective C++

页数:47 条款一: 把C++视为一种联邦语言,因为支持,过程,面向对象,函数,泛型,元编程。 C语言的次语言,有C,Object-Oriented C++。这部分也就是C with Classes;Template C++(泛型编程,一般经验较少);STL 条款二:尽量用const,enum,inline替换define 要是出错,编译器只会定位define替换的东西,不方便找问题。用

baidu_34674626的博客 600

Effective C++ 读书笔记(11-14)

Effective C++ 笔记

limingkang1的博客 1621

Effective c++ 读书笔记

说明 学习语言本身是一回事,学习如何使用这种语言进行设计和高效编程是另一回事。 这本书就是在有了一定的基础知识后,在实际项目开发和后续学习中的必读经典。它基于编程实际,以条款的形式描述了需要避开的坑和需要遵守的高效原则。 读过《c缺陷与陷阱》的朋友,可能在读这本书时能找到当时相同的感觉。 一口气读完了本书,余音绕梁,意犹未尽。重新翻阅本书,并作此记录,以供后续复习之用。 主要内容 习惯c+...

guotianqing的博客 352
上一篇: 《Effective C++》读书笔记之const高效使用
onelovefirst
博客等级 码龄19年 3粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值