天天看點

C++ 99 個常見錯誤 一

A.基礎問題

1.過分注釋(對注釋的更新與代碼不一緻), 字面常量(幻數,看不出意義, 可用 enum 或 const 解決).

2.全局變量.  

    <--幼稚的消息傳遞機制

    (1) 可用函數調用得到 (2) 可用一個類單例得到

3.未能區分函數重載和形參預設值.

4.引用:

   引用隻是其初始化物的别名.引用是沒有位址的,甚至不占有任何存儲空間. 由于無位址,聲明指向引用的指針,引用的引用都是不合法的。

    注:沒有空引用,也無類型為void的引用。任何可作為左值的都可被引用 .

    指向數組的引用 : int ( & array )[10] ;     <=保留了尺寸

    int f(double) ;     f(18.6) <=> (*f)(18.6)

5.對常量的誤區:

    const <- 常量,  10 <- 字面量

    const volatile <= 隻限制對const 的直接修改,間接修改是可行的,不會引發未定義的行為(??)

6.無視語言的精妙之處:

    (1) bool r = a < b ;       <=  never use if in this case !!! 不要用 if

    (2) 位屏蔽算法:      b & m & ((b & m) - 1)      ;;結果為0則沒選或隻選一個

    (3) 如果條件運算符表達式兩個選擇結果都為左值,那麼這個表達式就是左值 :

            a<b ? c: d < e ? d: e = val();

    (4) 内建索引運算符 :

          p[-2]  <=>  *(p + (-2))  <=> * ( -2 + p)  <=>  (-2)[p]

    (5) switch  <= 隻管入口,如果要直下,最好加上注釋.

         另:case 可不在同一級,case 可在任何地方.

7.空指針: #define NULL ((char * )0)  / ((void*)0)  / 0

       故,最好用 0 : C * cp = 0;

8.無視習慣用法:

   X ( const X &) ;      X & operator = ( const X &)

文法問題:

1. int * ip = new int(12) ;     //僅初始化了一個整數,并非一個數組

    int a[12] ; int a(12); 

    vector <int> iv(12);         <--下标通路,不用顯式回收

    注:最好的記憶體申請形式就是根本不做這個記憶體申請,直接用标準庫中元件.

2. 不定的求值順序:

    (a=12) + a

    a=( p() + q() ) + r();

    <---可以有六種順序

    Thing * pThing = new ( Thing ( initVal() ) ;

    <---可以肯定 operator new 會比 Thing 類型構造函數先調用(先配置設定空間,後初始化.)

     return  f(), g(), h();

     a = f() + g() ? p() : q(); <=> a = ( f() + g() ) ? p() : q();

     左結合性:該運算符先會綁定左邊那個參數;

     -> 有很高的優先級, 但是低于 ()

     ++ 高于 -> *

3. for 語句 

   if ( char * theName = lookUp( name )){ }

   for ( int i = 0 ; ; ){     }

4. 取大優先: list < vector < string >> lovos;    //  >>之間要有空格!!,不然會被當作...

5.聲明飾詞:  先連接配接,再量化,最後類型

   int const * const * pp1;    extern const int;

6. 是函數還是對象: String x(); <-函數聲明,多義    String x(void)

    String * sp1 = new String () ; <=> sp1 = m new String; (後面較好)

7.自反初始化:

   int var = 12;

   {

    double var = var;  // 未定義...        對枚舉則可行

    }   

8. 運算符名字查找的反常行為:

    中序文法調用:

    函數調用文法: 名字查找遵從标準形式

9 operator -> : 重載版本是一進制的,并且它必須傳回一個可用 -> 通路其成員的對象.

預處理問題:

1. #define 的作用域并未被限制在名字空間中;

    盡量不要用 #define 調用的僞函數. ---> static const ,函數對象,operator()

2. 如果調試代碼在最終生成的可執行檔案中根本不存在,那麼編譯器會剔除無用代碼...

    if( false ) { }

    避免用 #if 作為源代碼的控制.

3. assert 是一個宏 <--- 即也是一個僞函數.   #define assert(e) ((void) 0)

    ----->是以,當使用 assert 時,不要在 e 中使用函數調用.