effective c++ 笔记 (8)

//---------------------------15/04/09----------------------------

//#26   尽可能延后变量定义式的出现时间

{

/*  1:只要你定义了一个变量而其类型带有一个构造函数或析构函数,即使变量没有被使用

还是要承担构造或析构的成本。为了避免这种情况,应该尽可能延后变量定义式的出现

2:再一次重复条款4:直接给定一个初值来让对象初始化比先构造一个对象,再赋值效率要高。

3:对于循环的情况:

1>当赋值成本低于一组构造+析构成本时,可以把对象定义在循环外面。

2>反之,把对象定义在循环体内部。

3>效率相当时,应该把对象定义在循环体内部。

*/

}

//#27   尽量少做转型动作

{

/*  1:尽量使用C++的新式转型:

1>const_cast:

通常被用来讲对象的常量性去掉,它是唯一有此功能的转型操作符。

2>dynamic_cast:

执行安全向下转型,但是要耗费大量成本。

3>reinterpret_cast

参数必须是指针,只是转化类型,并不转化内部结构。

想比较于static_cast,static_cast在基类到子类转型时会计算偏移值,而

reinterpret_cast不会,所以这个转型很危险,尽量别用。

4>static_cast

除了去除const属性外,其他转型都行。

2:在类中不要对*this进行转型                                       */

class Window

{

public:

virtual void onResize(){...}

...

};

class SpecialWindow:public Window

{

virtual void onResize()

{

static_cast<Window>(*this).onResize();

}

};

/*    上面这样调用的是
转型时产生的副本(一个derived临时对象)的 base部分的那个函数。

所以不应该这么调用,而是使用Window::onResize();

3:dynamic_cast转型太慢了,能不用就不用,可以用两个方法避免这个转型:

1>直接使用derived类型的指针

2>在基类中定义一个无操作的virtual函数。

*/

}

//#28   避免返回handles指向对象内部成分

{

/*  1:如果返回一个handles(包括指针,引用,迭代器)指向对象内的private成员变量,那么外部就可以直接

修改这个成员变量了。虽然编译没错,但是这样就没有封装性可言了。

2:这带给我们两个教训:

1>成员变量的封装性最多只等于“返回其handles”的函数的访问级别。如果这个函数是public的

那么这个成员变量就是public的。

2>如果const成员函数传出一个handle,handle所指的数据与对象自身有关"private"或"protected"

而handle又被存储在对象之外,那么这个函数的调用者可以修改上面所指的数据。这是不合理的!!!

3:解决办法:

使返回指针和引用都是const就行了。

引用方式:                                                               */

const Point& upperLeft()
const { return pData->ulhc;}

//      指针方式:

const Point * upperLeft()
const { return pData;}

/*  4:返回一个handle代表对象内部成分
总是危险的,这是因为:

handle被传出去就有可能产生 handle比它所指对象生命周期更长。

也就是handle很有可能在某时刻指向不存在的资源:                                  */

GUIObject* pgo;

...

const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft());

//  这里只产生了一个临时对象,所以这条语句结束后就销毁了,而pUpperLeft也指向了已经销毁的对象资源

//  所以能避免返回handlers就避免吧。

}

//#29   为“异常安全”而努力是值得的

{

/* 1:“异常安全”有两个条件:

1>不泄漏任何资源。

解决办法是使用#13的办法,用对象(智能指针)来管理资源。

2>不允许数据败坏

2:异常安全函数提供三种保证之一:

1>基本承诺:如果异常被抛出,程序内的任何事物扔然保持在有效状态下。没有任何对象或数据结构会

因此而败坏,所有对象都处于一种内部前后一致的状态。然而程序的现实状态不可预料。

2>强烈保证:如果异常被抛出,程序状态不改变。调用这样的函数可以有这样的认知:如果函数成功,

就是完全成功,如果函数失败,程序会回到“调用函数前的状态”。

3>不抛掷(nothrow)保证:承诺绝不抛出异常。

3:我们的抉择:

1>有可能的话,提供nothrow保证。

大部分情况:

2>尽可能提供强烈保证,这里有一个好策略,不要为了表示某件事将要发生而改变对象状态,除非那件

事情已经发生了。

有一个好的策略会导致强烈保证:copy and swap。要做的事情就是:

1)先为要打算修改的对象copy一个副本。

2)把要做的事情都在副本上完成。

3)交换原对象和副本。

这里swap函数必须要能保证不抛出异常。

这个策略并不能保证整个函数有强烈的异常安全性。因为:

1)除了copy and swap外,如果还调用了其他函数,那么除非其他函数提供强烈异常保证

以上保证,不然就很难让整个函数提高强烈异常保证了。

2)即使其他函数提供了强烈异常保证,情况还是没有好转,因为其中一个函数改变了程序状态后

另外一个函数抛出了异常。

还有一件事会妨碍你提供强烈异常保证--效率问题,copy and swap带来的是一个对象的复制,

有时会消耗你无法承受的时间和空间。

3>当提供强烈保证不切实际时,就必须提供
基本保证。

但是有时候可能你连基本保证都无法提供,是的。

如果你调用的函数原本不提供保证,那~~除非不调用,不然就没有任何保证了。。。。。

为了别人不会遇到同样的痛苦,你必须尽可能为你的函数提供异常保证。

*/

}

时间: 2024-10-13 04:51:40

effective c++ 笔记 (8)的相关文章

Effective C++笔记:构造/析构/赋值运算

条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函数时,编译器会给我们构造默认的. 当成员变量里有const对象或引用类型时,编译器会不能合成默认的拷贝赋值函数:当一个基类把它的拷贝赋值函数定义为private时,它的派生类也不无生成默认的拷贝赋值函数,因为它无法完成基类成份的赋值. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 将拷贝构

Effective C++笔记06:继承与面向对象设计

关于OOP 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtual或non-virtual或pure-virtual. 3,成员函数和其他语言特性的交互影响:缺省参数值与virtual函数有什么交互影响?继承如何影响C++的名称查找规则?设计选项有如些?如果class的行为

Effective c++(笔记)之继承关系与面向对象设计

1.公有继承(public inheritance) 意味着"是一种"(isa)的关系 解析:一定要深刻理解这句话的含义,不要认为这大家都知道,本来我也这样认为,当我看完这章后,就不这样认为了. 公有继承可以这样理解,如果令class D以public 的形式继承了class B ,那么可以这样认为,每一个类型为D的对象同时也可以认为是类型为B的对象,但反过来是不成立的,对象D是更特殊化更具体的的概念,而B是更一般化的概念,每一件事情只要能够施行于基类对象身上,就一定可以应用于派生类对

Effective c++(笔记) 之 类与函数的设计声明中常遇到的问题

1.当我们开始去敲代码的时候,想过这个问题么?怎么去设计一个类? 或者对于程序员来说,写代码真的就如同搬砖一样,每天都干的事情,但是我们是否曾想过,在c++的代码中怎么样去设计一个类?我觉得这个问题可比我们"搬砖"重要的多,大家说不是么? 这个答案在本博客中会细细道来,当我们设计一个类时,其实会出现很多问题,例如:我们是否应该在类中编写copy constructor 和assignment运算符(这个上篇博客中已说明),另外,我们是让编写的函数成为类的成员函数还是友元还是非成员函数,

Effective C++笔记05:实现

条款26:尽可能延后变量定义式的出现时间 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被使用,而付出了构造成本来析构成本. 所以我们应该在定义对象时,尽可能的延后,甚至直到非得使用该变量前一刻为止,应该尝试延后这份定义直到能够给它初值实参为止. 这样做的好处是:不仅可以避免构造(析构)非必要对象,还可以避免无意义的default构造行为. 遇到循环怎么办?此时往往我

[Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

Effective c++(笔记)----类与函数之实现

上篇博客中集中说明了在设计一个类的时候常遇到的问题,当然博客中还夹杂着我随时想到的一些知识,发现自己写博客没很多人写的好,可能是自己语言不会组织,要么就是写的东西大家不愿意看,反正是有这方面的专业问题或者博客中有什么明显的错误和问题,大家提出来,我也好改进哈! 回归正题,这篇博客就大概的把Effective c++中类与函数这节看到的知识点做个笔记. 设计好一个类后,自己就要去实现这个类(实现类中的成员函数.友元.非成员函数等) 可能大家会遇到以下问题 1.在类的成员函数中,尽量避免返回内部数据

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

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用

java effective 读书笔记

java effective 读书笔记 [1]创建和销毁对象 1 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 2 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 3 枚举 singleton 不知道怎么操作,觉得意义不大 单例模式 4 私有化构造器不能实例化,也不可被子类继承 5 能用原生类的就尽量不用对象 [2]对于所有对象都通用的方法 reflexivity 自反性 symmetry 对称性 [3]类成员 降低可访问性 尽量把公有域 变成私有域,并提供

Effective c++(笔记) 之 杂项讨论

看到了Effective c++的最后一章,最开始的那章---内存管理还没搞清楚,准备那章搞清楚完也写篇博客,不管怎样,有好的开始就应该让它有个完美的结束,杂项讨论这章是作者将那些分到哪章都不合适的就索性放到了最后讨论,我看完后从中摘出自己认为重要的坐下笔记,如果能帮得到大家,那就更荣幸了哈! 1.当我们定义一个类时,编译器会自动给我产生哪些成员函数? 解析:我们都知道,当我们定义类时,如果我们没有定义某些成员函数的话,编译器会总会给我们自动合成,这就是编译器默默为我们完成和调用函数,这些函数主