您的位置:首页 > 编程语言 > C语言/C++

Effective C++ 笔记 第五部分 实现

2015-11-22 00:21 323 查看

26.尽可能延后变量定义式的出现时间(Postpone variable definitions as long as possible)

尽可能延后变量定义式的出现。这样做可以增加程序的清晰度并改善程序效率。

在变量定义式出现后,将调用构造函数,若该变量未被使用,则浪费效率。

不只要延后变量的定义,直到非得使用该变量的前一刻为止。甚至应该尝试延后这份定义直到能够给他初值实参为止。如果这样,不仅能避免构造和析构非必要对象,还可以避免无意义的default构造行为。

27.尽量少做转型动作(Minimize casting)

如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts。如果有个设计需要转型动作,试着发展无需转型的替代设计。

如果转型是必要的,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需要将转型放进他们自己的代码内。

宁可使用c++style转型,不要使用旧式转型。前者很容易辨识出来,而且也比较有着分门别类的职掌。

const_cast通常被用来将对象的常量性移除。

dynamic_cast指向“安全向下转型”,可能耗费重大的运行成本。

static_cast强迫隐式转换,如将non-const转为const,int转为double,void*转换为typed指针,pointer-to-base转为pointer-to-derived.

reinterpret_cast意图执行低级转型,如pointer to int转为int,不可移植,很少用。

之所以需要dynamic_cast,通常是因为想在一个你认定为derived class对象身上执行derived class操作函数,但手上只有一个指向base的pointer或reference,只能靠他们处理对象。有两个做法可避免这个问题。1、储存直接指向derived class的指针。2.在base class内提供virtual函数。

28.避免返回handles指向对象内部成分(Avoid returning “handles” to object internals.)

避免返回handles(包括reference、指针、迭代器)指向对象内部。遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生”虚吊号码牌”(dangling handles)的可能性降至最低。

返回handles指向对象内部成分的缺点:

使客户可以修改本被封装好的内部成员(private),破坏封装性。

若const函数返回handles将破坏函数的const性质。

若返回handles的对象删除了,则会得到一个指向不存在的对象的handles(虚吊号牌)

前两个缺点可返回const引用来去除,但是第三个问题使用const引用也不行。

29.为“异常安全”而努力是值得的(Strive for exception-safe code.)

异常安全函数即使发生异常也不会泄露资源或允许任何数据结构败坏。这样的函数区分为三种可能的保证:基本型、强烈型、不抛异常型。

”强烈保证“往往能够以copy-and-swap实现出来,但”强烈保证”并非对所有函数都可以实现或具备现实意义。

函数提供的”异常安全保证”通常最高只等于其所调用之各个函数的”异常安全保证”中的最弱者。

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

1.不泄露任何资源。

2.不允许数据败坏。

异常安全函数(Exception-safe functions)提供以下三个保证之一:

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

2.强烈保证:如果函数失败,程序会回复到“调用函数之前”的状态。

3.不抛掷(nonthrow)保证:承诺绝不抛出异常,总能完成承诺的功能,内置类型(int,指针等)的所有操作都是提供nonthrow保证的。

提供基本保证的几个技巧:

1.使用智能指针,可防止在delete语句执行前发生异常,导致delete没有执行。参考13.

2.以对象管理资源。

3.不要为了表示某件事发生而改变对象状态,除非那件事真的发生了。

提供强烈保证的技巧:

copy and swap策略可提供强烈保证。为你打算修改的对象(原件)做出一个副本,然后再那副本上做一切必要的修改,待所有改变成功后,在把副本和原件在一个不抛出异常的swap操作中swap(参考25)。若任何修改动作抛出异常,原对象仍然保持未改变状态。

30.透彻了解inlining的里里外外(Understand the ins and outs of inlining)

将大多数inlining限制在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制升级更容易,也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。

不要只因为function templates出现在头文件,就将他们声明为inline。

inline只是对编译器的一个申请,不是强制命令。这项申请可以隐喻提出,也可以明确提出。隐喻方式是将函数定义于class定义式内。

大部分编译器拒绝太过复杂的函数inlining(例如带有递归或循环),所有对virtual函数的调用也会使inline被拒绝。

编译器通常不对通过函数指针进行的调用inlining,因为在编译期无法提出该指针。

inline函数无法随着程序库的升级而升级。一旦改变该函数必须重新编译。

31.将文件间的编译依存关系将至最低(Minimize compilation dependencies between files.)

支持”编译依存性最小化”的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes 和 Interface classes.

程序库头文件应该以”完全且仅有声明式”的形式存在。这种做法不论是否涉及templates都适用。

使用声明依存性替换定义依存性是降低编译相依的策略。

降低编译依存性的方法:

1.如果使用object reference 或object pointers可以完成任务,就不要使用object。

指出一个类型的reference只需要该类型的声明式,因为指针大小是固定的。但定义某类型的object则需该类型的定义式,因为编译器需要知道其大小以分配内存。

2.如果能够,尽量以class声明式替换class定义式。

使用声明式而不使用该类型不会增加编译依存性。

class Data;//class声明式
Data today();


3.为声明式和定义式提供不同的头文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++