std::string str;
str = password;
…
//将password作为encrypted的初值,跳过毫无意义的default构造过程
std::string str(password);
…
上述行为可以避免构造非必要对象,还可以避免无意义的default构造行为。
* 尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率。
### 27:尽量少做转型动作
C风格的转型
(T)expression
T(expression)
C++提供的四种新式转型
const_cast(expression)//通常用来将对象的常量性转除,唯一有此能力的c++风格转型操作符
dynamic_cast(expression)//安全向下转型,用来决定某对象是否归属继承体系的某个类型,可能耗费重大运行成本。
reinterpret_cast(expression)//执行低级转型,实际动作可能取决于编译器,表示它不可以移植
static_cast (expression)//强迫隐式转换,它不能将const转换成non const,只有const_cast能做到
使用C++新式转型的好处:容易在代码中辨识出来;各转型动作越窄化,编译器越可能诊断出错误的运用
使用旧式转型的时机:调用一个explicit构造函数将一个对象参数传递给一个指针时。
* 如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic\_casts。如果又个设计需要转型动作,试着发展无需转型的替代设计。
* 如果转型是必要的,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需将转型放进他们自己的代码内。
* 宁可使用新式转型,不要使用旧式转型。前者容易辨识出来,而且也比较有着分门别类的职掌。
### 28:避免返回handle指向对象内部
1.类的const成员函数不允许在该函数内部修改该类的成员变量,但是当该函数返回指向对象成员变量的handles,这就会使外部能通过这个handle修改对象的成员变量,这个是矛盾的。解决方法是:返回值加上const (const xxx& yyy()const {…})。
2.如果返回对象的成员变量被析构,这样的话,对象里的成员变量就会指向一个不存在的对象,旧变成虚吊。这是非常危险的。
3.不意外着绝对不可以让成员函数返回handle,有时候你必须这么做。例如:strings[] vector[]
* 避免返回handles(包括引用,指针,迭代器)指向对象内部,遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”的可能性降到最低。
### 29:为“异常安全”而努力是值得的
当异常抛出时,带有异常安全性的函数会:
1.不泄露任何资源-有一条语句(比如new语句)抛出异常,会后面的语句无法执行,如果后面的语句是解锁,这样的话,锁就永远也不会放开了。解决方法:采用一个类确保锁能及时被释放
2.不允许数据败坏-当new出现异常,该变量就会指向一个已被删除的对象,应该就对象已经被删除了,创建新对象抛出异常。
3.基本承诺-如果异常抛出,程序内的任何失误仍然保持在有效状态下。没有任何对象或数据结构会因此而败坏,所有对象都处于一种内部前后一致的状态。
4.强烈保证:如果异常被抛出,程序状态不改变。认知:如果函数成功,要完全成功,如果函数失败,要回到调用函数之前的状态。
5.不抛掷保证:承诺绝不抛出异常,作用于内置类型的操作符都提供nothrow保证。
* 异常安全函数即使发生异常也不会泄露资源或允许任何数据结构败坏。这样的函数区分为三个可能的保证:基本型,强烈型,不抛异常型
* 强烈保证往往能够以copy and swap实现出来,但强烈保证并非对所有函数都可 实现或具备显示意义。
* 函数提供的异常安全保证通常最高只等于其所调用之各函数的异常安全保证中的最弱者。
### 30:透彻了解inline的里里外外
优点:没有函数调用的额外开销
缺点:程序体积太大,会导致额外的换页行为,降低指令高速缓冲器装置的击中率,以及伴随而来的效率损失。
1.**inline只是对编译器的一个申请,不是强制命令**。这项申请可以隐式提出(将函数定义于类定义式内),也可以明确提出(加上关键字inline)。
2.inline函数通常一定被置于头文件内,因为大多数建置环境在编译过程中进行inline,为了将函数调用替换成函数本体,编译器必须知道那个函数长什么样子。Template通常也被置于头文件内,编译器为了将它具现化,需要知道它长什么样子。
3.一个表面上是inline的函数是否是真的inline,取决于你的建置环境,主要取决于你的编译器。
**平均而言一个程序的80%执行时间花费在20%的代码上。**-找出那20%的代码,然后将它inline或竭尽所能将它瘦身。
* 将大多数inlining限制在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制升级更容易,也可以使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。
* 不要只因为funciton templates出现在头文件,就将它们声明为inline。
### 31:将文件间的编译依存关系将至最低
原因:因为头文件中内容的修改,会导致所有该头文件的文件必须重新编译。
解决方法:声明依存性替换定义的依存性。这正是编译依存性最小化的本质。
eg:将对象实现隐藏于一个指针背后,这般设计常被称为pimpl idiom(pointer to implementation)
class Person
{
public:
std::string name()const;
std::stirng birthDate()const;
…
private:
std::tr1::shared_ptr pImpl;//指针,指向实现物体 tr1::shared_ptr<>智能指针
};
1.如果使用对象引用或对象指针可以完成任务,就不要会使用对象。
2.如果能够,尽量以类声明式代替类定义式。