Effective c++ 1 1...4

导读

Pass-by-value意味着调用copy构造函数。

尽可能避开undefined behavior。

条款01:视c++为一个语言联邦。

四个次语言,C、OO、template、STL。

每个次语言都有自己的规约。

当从一个次语言切换到另一个次语言时,高效编程的守则要求你改变策略…用哪种策略?取决于你使用C++的哪一个部分。

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

#define不提供任何封装性。#define到#undef之间均可见。

#define有可能被编译器忽视,没进入symbol table。

const double AspectRatio = 1.653;代替 #define ASPECT_RATIO 1.653

const char* const autorName = “S M”;

const std::string autorName = “S M”;


 

enum hack技术提供三个好处:

1、  编译器不支持类内给static const int 赋初值,而你又需要用。Just as a note also, it was most useful when defining array sizes which need to be known when a class is declared Where you would probably want to do this with a static constant, as the compiler did not support it, it would work correctly with an enum declaration.

1 class GamePlayer{
2 /*static const int NumTurns = 5;*/
3  enum{NumTurns = 5};
4  int scores[NumTurns];
5 };
6 //const int GamePlayer::NumTurns;

2、  取一个enum的地址不合法,你需要这种约束,不希望某个pointer或者reference获得你的整数常量。

3、  enum绝不会导致非必要的内存分配。



1
// 2 template< typename T > 3 inline void callWithMax(const T& a, const T& b) 4 { 5 f( a>b ? a : b ); 6 } 7 //代替 8 #define CALL_WITH_MAX(a,b) f( (a)>(b) ? (a) : (b) )

#include  #ifdef/#ifndef 仍在使用

条款003:尽可能使用const

1、  

  const在*左侧,对象是常量  const char* p;  

              char const* p;

const在*右侧,指针是常量   char * const p;

2、const可以帮助编译器侦测出错误的用法。

1 class Rational{
2 const Rational operator*( const Rational& lhs, const Rational& rhs) };
3 Rational a,b;
4 //a*b 的结果是const 就避免了a*b == c 错写成 a*b=c时的赋值。

 3、类可以产生const对象(不变的对象),这种const对象只能调用const成员函数,const成员函数保证(不变的对象)这点。

类有成员函数和const成员函数,这两种成员函数的区别关键是 this指针。const成员函数的this指针是 const指针。自然也只能返回const的this指针/const的this对象引用(如果没有强转的话)。不改变const对象。

当我的const对象的某些位确实需要修改的,const成员函数需要修改const对象的个别位个别数据成员时,用mutable释放掉这个数据成员的const,绕过编译器的bitwise constness要求。

 1 class cTextBlock{
 2 public:
 3     size_t length() const;
 4 private:
 5     char* pText;
 6     /*mutable*/size_t textLength;
 7     /*mutable*/bool lengthIsVaild;
 8 };
 9 
10 size_t cTextBlock::length() const
11 {
12     if (!lengthIsVaild)
13     {
14         textLength = std::strlen(pText);
15         lengthIsVaild = true;
16     }
17     return textLength;
18 }
19 
20 /*我还是需要length()是const函数,在取length的时候不打算改变pText指向的文字内容,const对象可以保证不改变文字内容的情况下获得文字长度。这是逻辑上的const需求。
21 
22 但是textLength和lengthIsVaild成员在求length的时候要改变,length()const成员函数需要改变const对象的个别数据成员textLength和lengthIsVaild,那么就把这两个数据成员设成mutbale!*/

4、在const和non-const成员函数的实现中避免重复

令non-const成员函数调用const的重载版本来实现自己,避免代码重复。

调用重载版本不能直接用名字调,会递归自身。而是把this强转为 const this ,然后用const this执行的调用就是调的const版本的了。 调用完const版本后的返回类型可能是const的,视需要强转为non-const版本的。至此,完成non-const版本函数的实现。

const_cast<[const] T >( …);

条款004: 对象被使用前已经初始化

1、 内置类型对象 2、类数据成员对象 3、static对象

1、 内置类型对象。

定义的时候就初始化它。作为类数据成员的时候,在初始化列表里一块儿了。

2、 类数据成员对象。

对象成员变量的初始化动作发生在进入构造函数本体之前。推出1:初始化列表里完成。推出2:初始化时的try-catch应该在初始化列表处。

节省成本:

初始化列表的过程:调用一次copy构造。

构造函数本体中赋值的过程:先调一次default构造,再调一次copy assignment。 

适用不能赋值的成员:const和reference类型成员,这种成员必须被初始化。

如果构造函数N多,又不想一一写初始化列表:

可以适当遗漏 “赋值表现和初始化一样好”的成员变量,把这些成员变量的赋值写到一个private函数里,然后让N个构造函数调用这个函数。适用于“初值是由文件或者数据库读入”的情况。不过,这终归是“伪初始化”。

C++有十分固定的成员初始化次序:先初始化基类的,然后初始化派生类的。类中按照声明次序初始化。 推出:初始化列表的次序不决定初始化次序,还是写得和声明次序一样比较好。

初始化列表中可能是这种形式:先基类的(像调用基类构造函数似的),然后是自己类的成员变量的(按照声明次序)。

3、 static对象。

生命:从被构造出来到程序结束为止。

有哪些种:

local static:在函数内部定义的static对象。local static对象在“该函数被调用期间”,“首次遇上该对象之定义式”时被初始化。

non-local static:不在函数内的(global的、namespace内的、class内的、file作用域内的)


 

编译单元:产生单一目标文件的那些源码:若干.h文件+源码文件。最后形成一个single object file。估计就一个main。???

问题:不同编译单元中定义的non-local static对象的初始化次序不确定

 1 //编译单元1file1
 2 class Filesystem{
 3     size_t numDisk() const;
 4 };
 5 extern Filesystem tfs;
 6 
 7 //编译单元2file2
 8 class Directory{
 9 public:
10     Directory(params);
11 };
12 
13 Directory::Directory(params){
14     size_t disks = tfs.numDisk();
15 }
16 
17 int main() { 
18     
19 Directory tempDir(params);
20 
21     }
22 /*构造tempDir对象的时候,需要用到tfs对象。需要保证tfs对象构造在tempDir对象构造之前。这个,C++是不保证的。我们如何保证?*/

把static放到函数里,变作local static,这个函数返回static的引用。第一次调用这个函数时,local static被构造,然后返回它的引用,就获得了一个保证被构造的static对象。还可以根据调用函数的次序保证构造次序。

 1 //编译单元1file1
 2 class Filesystem{
 3     size_t numDisk() const;
 4 };
 5 inline Filesystem& tfs(){//reference-returning 函数
 6 static Filesystem fs;
 7 return fs;
 8 }
 9 
10 //编译单元2file2
11 class Directory{
12 public:
13     Directory(params);
14 };
15 
16 Directory::Directory(params){
17     size_t disks = tfs().numDisk();
18 }
19 Inline Directory& tempDir(){//reference-returning 函数
20      static Directory td;
21      return td;
22 }
23 
24 int main() { 
25     tempDir();
26     }

多线程中使用 non-const static有问题。

解决1:在程序的单线程启动阶段手工调用全部的reference-returning函数,可以消除与初始化有关的竞速形势(race condition)。

解决2:双检测锁。

posted @ 2013-02-22 14:41  浑身胆满脸魄  阅读(170)  评论(0编辑  收藏  举报