//---------------------------15/03/30----------------------------

//#13   以对象管理资源

{

void f()

{

Investment *pInv = createInvestment();

...

delete pInv;

}

/*

1:这里很容易出现内存泄漏:

1>...中过早地return。

2>...中抛出异常。

2:为了确保pInv总是被释放,我们需要将资源放进对象内,当控制流离开f时,

这个对象会自动调用析构函数释放掉资源。

3:这里有两个常用的智能指针可以实现:

1>std::auto_ptr。使用方法:std::auto_ptr<Investment> pInv(createInvestment());

记得不要让多个auto_ptr同时指向一个对象,这样会造成多次delete。为了预防这个问题,auto_ptr

在被copy给别的指针时,会变成null。

2>tr1::shared_ptr。这个智能指针使用引用计数,在被copy一次后会自动计数加1,调用一次析构函数

会自动计数减1,当计数为0时销毁对象。

唯一的问题是循环引用。两个没有被使用的对象相互指着对方,这样看起来好像都在使用中,然而并不是这样。

4:如果要对申请到的数组资源使用智能指针,可以使用boost::scoped_array和boost::shared_array

这两个在析构时调用delete[];

*/

}

//#14 在资源管理类中小心coping行为

{

//  auto_ptr和tr1::shared_ptr不适合掌管非heap-based资源。这时候需要自己建立资源管理类

class Lock

{

public:

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

{

lock(mutexPtr);

}

~Lock()

{

unlock(mutexPtr);

}

private:

Mutex *mutexPtr;

};

/*  这时会出现一个问题:如果对象被复制,这个锁会被再锁上一次。如果是在同一线程中这么做

程序就死锁了,无法再恢复。所以大多数时候,可以选择以下两种处理。

1>禁止复制。像Lock这样的class,这样处理是科学的。可以从Uncopyable那用私有继承。

2>对底层资源使用“引用计数法”。Mutex的“引用计数”版本可以使用tr1::shared_ptr,并

指定“删除器”,当引用次数为0时,“删除器”会被调用。代码看起来像这样: 
              */

class Lock

{

public:

explicit Lock(Mutex* pm):mutexPtr(pm, unlock)

{

Lock(mutexPtr.get());

}

private:

std::tr1::shared_ptr<Mutex> mutexPtr;

};

/*  有时候会有两种特殊的需求:

1>复制底部资源(深拷贝)。这是为了当你不需要某个复件时确保它被释放,所以拷贝时要连同

指针指向的资源一起拷贝,不然原始对象删除后就没法用了。

2>转移底部资源的拥有权。就像auto_ptr一样。

*/

}

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

{

/*  1:在资源管理类中,常常需要提供对原始资源的访问,原因是:一些api需要的就是原始资源

如果传入一个资源管理类,它们并不起作用。

2:提供对原始资源访问的方法有二:

1>提供显示访问:                                                   */

class Font

{

public:

explicit Font(FontHandle fh): f(fh)

{}

~Font() { releaseFont(f);}

FontHandle get()const {return f;}

private:

FontHandle f;

};

/*      这样一来就可以通过调用get()来访问原始资源了,但是每次都要用f.get(),显得十分麻烦。

2>提供隐式转换函数:

operator FontHandle() const {return f;}

但是这么做,存在风险,客户有时候笔误就会造成获得一个错误的类型:                */

Font f1(getFont());

...

FontHandle f2 = f1;//本来客户是想要 Font f2 = f1;

/*      但是就算这么调用了,客户也看不出来,因为隐式转换的关系,表达式是可以编译通过的。

而且使用起来也是一样的。最后,当f1被销毁时,问题来了,f2就成为“虚吊的”,就是指向

的资源以及被释放。

3:两种设计各有优势,为了安全倾向显示转换,为了方便倾向隐式转换。

4:RAII class返回原始资源与封装发生矛盾,这是真的。但是并没有关系,RAIIclass是为了确保

资源一定会被释放,而不是为了封装。

*/

}

//#16  成对使用new和delete时要采用相同形式

{

/*  1:当使用new时,有两件事情发生:

1>内存被分配出来。

2>针对此内存会调用构造函数(一个或多个)。

2:当使用delete时,也有两件事发生:

1>先调用析构函数(一个或多个)

2>释放内存。

3:数组对象的内存中一般还包含一个数组大小的记录,以便delete知道需要调用多少次析构函数

所以在调用时必须成对出现,不然会发生不可预测的情况。

4:使用typedef时,最好不要对数组进行typedef。

比如: typedef std::string AddressLines[4];

这样很容易错误地使用delete,所以应该避免这种定义。                            */

}

//#17   以独立的语句将newed对象置入智能指针

{

//  看一个函数调用:

processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());

/*  这样调用有可能造成内存泄漏,首先,编译器为了效率问题执行以下顺序:

1>new widget;

2>priority();

3>tr1::shared_ptr的构造函数

如果priority()的调用导致异常,那么new Widget返回的指针就遗失了,内存就泄漏了。

所以为了避免着问题很简单:                                               */

std::tr1::shared_ptr<Widget> pw(new Widget);

processWidget(pw, priority());

//  把newed对象置入智能指针的操作用独立语句来实现,这样就不会产生内存泄漏了。

}

effective c++ 笔记 (13-17)的更多相关文章

  1. CSS3秘笈第三版涵盖HTML5学习笔记13~17章

    第13章,构建基于浮动的布局 使用的是float(浮动)属性 注:float:none值将取消所有浮动,通常只用来取消元素中已经应用的浮动. 切记:不需要给正文的div设计宽度,即使设计成固定宽度也不 ...

  2. effective c++ 笔记 (1-3)

    // //  effective c++.cpp //  笔记 // //  Created by fam on 15/3/23. // // //-------------------------- ...

  3. [Effective JavaScript 笔记]第17条:间接调用eval函数优于直接调用

    eval函数不仅仅是一个函数.大多数函数只访问定义它们所在的作用域,而不能访问除此之外的作用域(词法作用域).eval函数具有访问调用它时的整个作用域的能力.编译器编写者首次设法优化js时,eval函 ...

  4. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  5. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  6. SQL反模式学习笔记13 使用索引

    目标:优化性能 改善性能最好的技术就是在数据库中合理地使用索引.  索引也是数据结构,它能使数据库将指定列中的某个值快速定位在相应的行. 反模式:无规划的使用索引 1.不使用索引或索引不足 2.使用了 ...

  7. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  8. 机器学习实战 - 读书笔记(13) - 利用PCA来简化数据

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第13章 - 利用PCA来简化数据. 这里介绍,机器学习中的降维技术,可简化样品数据. ...

  9. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  10. [Effective JavaScript 笔记]第3章:使用函数--个人总结

    前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...

随机推荐

  1. EmEditor的一个好用的正则替换功能

    最近在编辑文本的时候用到了EmEditor的一个好用的正则替换功能.即我想用搜索到内容的一部分来生成另一段文本.例如客户提供给我一大堆MYSQL的建立主键的脚本,我想改成MSSQL的建立主键的脚本,这 ...

  2. 使用mysqldump备份时为什么要加上 -q 参数(5.7默认为on)

    使用mysqldump备份时为什么要加上 -q 参数(5.7默认为on) 写在前面:我们在使用mysqldump备份数据时,请一定记住要加上 -q 参数,后果可能是很严重的,不要给自己挖坑哦. 先来看 ...

  3. iftop – 实时Linux网络带宽监控工具

    在本文中,我们提出了另一个称为Interface TOP (IFTOP)的优秀程序, 它是一个基于实时控制台的网络带宽监控工具. 它将显示接口上网络活动的快速概览. Iftop 平均每 2,10 和4 ...

  4. gnome-shell 使用 notify-send 发送桌面消息

    什么是notify-send? notify-send - a program to send desktop notifications 怎么使用? NAME notify-send - a pro ...

  5. Java-Swing常用布局管理器

    http://www.cnblogs.com/hthuang/p/3460234.html   5.Java-Swing常用布局管理器       应用布局管理器都属于相对布局,各组件位置可随界面大小 ...

  6. 何为用户体验?附《用户体验的要素》PDF版下载

    一.什么是用户体验? 用户体验(User Experience,简称UE/UX)是用户在使用产品过程中建立起来的一种纯主观感受.但是对于一个界定明确的用户群体来讲,其用户体验的共性是能够经由良好设计实 ...

  7. [MySQL]在安装windows版MySQL时遇到过如下问题Error Nr.1045和Error.Nr.2003,相应解决办法如下

    1.准备mysql server-5.0.27.exe 2.按照指导安装,在安装到最后一步时遇到如下两个错误: 2.1.出现错误Error Nr.1045 解决办法: a).停止MySQL服务:我的电 ...

  8. 【Ansible 文档】【译文】网络支持

    Networking Support 网络支持 Working with Networking Devices 使用网络设备 自从Ansible 2.1开始,你现在可以使用成熟模型 - 编写 play ...

  9. loli的混合算法测试

    最近刚讲了最短路,说要考试我以为是考最短路,然而只有一道是最短路... 数据似乎有一点问题,不管了,反正手工测评都是对的,那现在就来看看题吧. Balanced:(此处并没有网址) 题意概述:$n$  ...

  10. Unicode,GBK,GB2312,UTF-8概念基础(转载)

    第一篇:JAVA字符编码系列一:Unicode,GBK,GB2312,UTF-8概念基础本部分采用重用,转载一篇文章来完成这部分的目标.来源:holen'blog   对字符编码与Unicode,IS ...