天天看点

Effective C++ 5

 通过default构造函数出一个对象再对他赋值比直接在构造时指定赋值 差。

比如

string str("honey~");和

string str; str="honey~";效率就不一样。

接下来讲循环时的初始化,

class A;

for(int i=0;i<n;i++)  //n次构造,n次析构

{

   A a(**);

}

//综上,下面的情况好。

转型分为旧式转型和新式转型。

旧式转型: (T) expression

新式转型:

1.const_cast<T>(expression)  cast away the constness

将对象的常量性移除

2.dynamic_cast<T>(expression) safe downcasting

唯一不能用旧式转型实现的转型动作。不过可能耗费重大运行成本的动作。

3.reinterpret_cast <T>(expression) 低级转型

例:int*->int

4.static_cast<T>(expression) 强迫隐式转换。

例:non-const  -> const ,int->double

     pointer-to-base  ->pointer-to-derived

     void*  -> typed 指针

现在运用旧式转型符的时机是调用explicit构造函数。

handle:reference,指针,迭代器。

函数不要返回一个指向访问级别较低的成员函数。因为会降低封装性。

成语函数返回对象内部的handle可能会使dangling。

下面来看异常:

异常安全函数保证:

1.基本承诺:异常不出错即可能出于任何合法状态。

2.强烈保证:异常返回前一状态。

3.不投掷保证:不跑出异常。

如int f() throw();   //不是说不抛出异常,而是只要抛出异常,就导致严重错误。

动态分配不成功就 bad_alloc异常。

如果一个系统中有一个函数不具备异常安全性,则整个系统不具备异常安全性。

封装,异常安全性。

inline函数

1.免除调用成本

2.如果函数体过大,则会换页行为和降低指令高速缓存装置的击中率。

3.对比函数本体和函数调用所产生的代码长度。

4.因为inlining是编译期行为,所以要在头文件中。

5.template通常也 是inline但不全是。

//此实例为了证明构造函数和析构函数最好不要inline

class Base

{

public:

...

private:

string bm1,bm2;

};

class Derived

{

public:

Derived(){} //看起来是空的。

private:

stirng dm1,dm2,dm3;

};

Derived::Derived()

{

Base::Base();

try{dm1.string::string();}

catch(...)

{

Base::~Base();

throw;

}

try{dm2.string::string();}

catch(...)

{

dm1.string::~string();

Base::~Base();

throw;

}

try{dm3.std::string::string();}

catch(...)

{

dm2.string::~string();

dm1.string::~string();

Base::~Base();

throw;

}

}

pimpl idiom 将实现放入一个类,在接口类中定义一个智能指针指向实现类,从而达到与实现细目分离。