Just a little smile ^ ^

yoyo_zeng

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1.       让自己习惯C++

 条款1: C++为一个语言联邦

条款2: 尽量以const, enum, inline替换 #define

条款3: 尽可能使用const

条款4: 确定对象被使用前已先被初始化

 

2.       构造/析构/赋值运算

条款5: 了解C++默默编写并调用哪些函数

条款6: 若不想使用编译器自动生成的函数,就该明确拒绝

可以将copy constructor or copy assignment声明为private,且不定义.


条款7: 为多态基类生命能够virtual析构函数

条款8: 别让异常逃离析构函数

析构函数抛出异常会导致不明确行为,在析构函数中捕捉.

 

条款9: 绝不在构造和析构过程中调用virtual函数.

 class baseclass

{

         baseclass()

         {

                   func(); /*此时对象类型为baseclass, 调用的是baseclass中的func, 因为derivedclass变量尚未初始化,所以不可能调用derivedclass中的函数(会调用derivedclass中的变量)*/

         }

         virtual void func(void) const

         {

         }

};

条款10: operator= 返回一个reference to *this

条款11: operator= 中处理自我赋值

确定操作对象是同一对象时,其行为仍然正确.


条款12: 复制对象时,勿忘其每一个成分


 3.       资源管理

条款13. 以对象管理资源

使用RAII对象,他们在构造函数中获得资源并在析构函数中释放资源,两个常被使用的RAII class tr1::shared_ptrauto_ptr.


条款14: 在资源管理类中小心copying行为

shared_ptrauto_ptr管理的是heap-based资源,有时候并不适合管理其他资源,所以你需要建立自己的资源管理类.

using namespace System;

using namespace  System::Threading;

 class Lock

{

public:

         explicit Lock(Mutex *pm)

                   : mutexptr(pm)

         {

                   lock(mutexptr);

         }

 

         ~Lock()

         {

                   unlock(mutexptr);

         }

private:

         Lock(const Lock &); //禁止复制

         Mutex *mutexptr;

};

可以改写为:

class Lock

{

public:

         explicit Lock(Mutex *pm)

                   : mutexptr(pm, unlock) /*shared_ptr允许指定删除器,一般为一个函数或者函数对象,当引用次数为0时,自动调用删除器,auto_ptr无,第二个参数默认为NULL*/

         {

                   lock(mutexptr.get()); //获得资源

         }

 private:

         Lock(const Lock &); //禁止复制

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

};

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

如同shared_ptrauto_ptr,调用get()函数返回原始指针,或者使用隐式转换,将资源管理类转换为原始指针 operator ptr();


条款16: 成对使用newdelete, 要采取相同形式

new – delete, new [] – delete []


条款17: 以独立语句将newed对象置入只能指针

func(std::tr1::shared_ptr<myclass>(new myclasss), func2());

也许编译器执行顺序为new, func2, call shared_ptr constructor, 如果func2异常,则new指针遗失且内存泄露.所以独立将new对象置入只能指针.

std::tr1::shared_ptr<myclass> ptr(new myclasss);

func(ptr, func2());

 

4.       设计与声明

条款18: 让接口容易被正确使用, 不易被误用

条款19: 设计class犹如设计type

条款20: 宁以pass-by-reference-to-const替换pass-by-value

pass-by-value可能被切割,而引用往往以指针实现,pass by reference通常意味这真正传递的是指针,所以内置对象一般pass-by-value效率高些,也适用于STL的迭代器和函数对象,因为习惯上他们设定为passed by value.

 

条款21: 必须返回对象时,不要返回其reference

返回其副本,不能是局部变量的引用(销毁)local static(同一内存)变量或者new(无法delete).

 

条款22: 将成员变量声明为private

条款23: 宁以non-member, non-friend替换member函数

条款24: 若所有参数皆需类型转换, 请为此采用non-member函数

class rational

{

public:

         const rational operator *(const rational &rhs) const;

}

rational result;

rational onehalf;

result = onehalf*2; //ok, result.operator *(2);

result = 2*onehalf; //error, 2.operator *( result);

即使

class rational

{

public:

rational(int); //隐式转换

         const rational operator *(const rational &rhs) const;

}

result = 2*onehalf; //error,因为只有当参数被列于参数列内,参数才可以进行隐式转换.

所以将operator *设为non-member函数

const rational operator *( const rational &lhs,const rational &rhs);

 

条款25: 考虑写出一个不抛异常的swap函数

如果在你的class中需要改写swap,那么也该提供一个non-member swap来调用前者.

class rational

{

public:

         void swap(rational &)

         {

                   using std::swap;

                   ...

         }

};

namespace std

{

         template<> void swap<rational>(rational &a, rational &b)

         {

                   a.swap(b);

         }

}

如果rationaltemplate

template <class T>class rational

{

public:

         void swap(rational &)

         {

                   using std::swap;

                   ...

         }

};

namespace std

{

         template<class T> void swap(rational<T> &a, rational<Y> &b) /*重载, 但是error,可以特化std里面的templates,但是不可以添加新的templatesclassedfunctions或其他任何东西, std里面的东西完全由C++标准委员会决定.*/

         {

                   a.swap(b);

         }

}

namespace rationalstuf

{

         template <class T>class rational

         {

         public:

                   void swap(rational &)

                   {

                            using std::swap;

                            //...

                   }

         };

         template<class T> void swap(rational<T> &a, rational<T> &b) //ok

         {

                   a.swap(b);

         }

}

 

5.       实现

条款26: 尽可能延后变量定义式的出现时间

条款27: 尽量少做转型动作

const_cast<T>(expression) //const转换为non-const

dynamic_cast<T>(expression) //安全像下转型,baseclass change to derivedclass

reinterpret_cast<T>(expression) //执行低级转换

static_cast<T>(expression) //强迫隐式转换

使用C++ stytle转型,不要使用就是转型,避免使用dynamic_cast

 

条款28: 避免返回handles指向对象内部成分

class myclass

{

public:

         int &get(){return m_i;}

private:

         int m_i;

};

降低对象封装性,而且有可能使用handle时,对象可能被析构.

 

条款29: 为"异常安全"而努力

当异常抛出时,不泄漏任何资源,不允许数据破换.

 

条款30: 透彻了解inlining的里里外外

inlinetemplate都是编译器行为,被置于头文件中,因为inlining将函数调用替换为本体,所以需要知道函数定义,同样,template需要实例化也需要知道定义.

virtual函数会让inline落空,因为virtual是运行期决定,而inline是编译时决定.

inline无法随程序库的升级而升级,客户程序必须重新编译.

 

条款31: 将文件间的编译依存关系降至最低

相依于声明式,不要相依于定义式.

posted on 2011-09-29 15:51  yoyo_zeng  阅读(219)  评论(0编辑  收藏  举报