Effective C++筆記(一)——條款26-29

條款26:儘量延後變量定義式的出現時間


爲什麼要儘可能延後?

當程序中途跳出而致使變量未被使用,可是必須進行構造和析構。安全


最佳初始化變量

直接在構造時指定初值比構造以後再賦值效率高(條款4)數據結構

...
   std::string encrypted(password);
   ...

循環內變量定義在循環內仍是循環外?

程序A:定義於循環外

//方法A:循環外定義
   POINT point;
   for (int i = 0; i < 1000000000; i++)
   {
    point = tmp;
    //tmp = point;
   }

程序B:定義於循環內

//方法B:循環內定義
   for (int i = 0; i < 1000000000; i++)
   {
    POINT point(tmp);
    //tmp = point;
   }

測試程序

int PostponeVariable()
   {
    POINT tmp;
    tmp.x = 12;
    tmp.y = 13;

    clock_t start = clock();
    //方法A:循環外定義
    POINT point;
    for (int i = 0; i < 1000000000; i++)
    {
        point = tmp;
        //tmp = point;
    }
    clock_t end = clock();
    printf("A:%ld\n", (end - start));

    start = clock();
    //方法B:循環內定義
    for (int i = 0; i < 1000000000; i++)
    {
        POINT point(tmp);
        //tmp = point;
    }
    end = clock();
    printf("B:%ld\n", (end - start));

    return 0;
   }

結果

A:2953
B:2774
請按任意鍵繼續. . .函數

所有都是A比B執行的快,以前一直自覺得是的以爲放在循環外效率比較高!測試


條款27:儘可能少作轉型動做

  1. 儘可能避免轉型,特別是dynamic_casts,使用無轉型設計代替有轉型設計
  2. 必定要轉型時,試着將其影藏於函數背後
  3. 儘量使用C++新式轉型

條款28:避免返回handles指向對象的內部

class Point{ 
public: 
    Point(int x, int y); 
    ... 
    void setX(int newVal); 
    void setY(int newVal); 
    ... 
}; 
struct RectData{ 
    Point ulhc; 
    Point lrhc; 
}; 
class Rectangle{ 
    ... 
    Point& upperLeft()const {return pData->ulhc;} 
    Point& lowerRight()const {return pData->lrhc;} 
private: 
    std::tr1::shared_ptr<RectData> pData; 
};

const對象被修改:設計

Point coord1(0,0); 
Point coord2(100,100); 
const Rectangle rec(coord1, coord2); 
rec.upperLeft().setX(50);//如今rec變成從(50,0)到(100,100)

修正:指針

class Rectangle{ 
    ... 
    const Point& upperLeft()const {return pData->ulhc;} 
    const Point& lowerRight()const {return pData->lrhc;} 
private: 
    std::tr1::shared_ptr<RectData> pData; 
};

避免返回指向對象內部部件的句柄(引用、指針或迭代器)。這樣作能夠加強封裝性,幫助 const 成員函數擁有更加「 const 」的行爲,而且使「野句柄」出現的概率降至最低。code


條款29:爲「異常安全」而努力

1. 修改菜單背景

class PrettyMenu{ 
public: 
    ... 
    void changeBackground(std::istream& imgSrc); 
    ... 
private: 
    Mutex mutex; 
    Image* bgImage; 
    int imageChanges; 
}; 
void PrettyMenu::changeBackground(std::istream& imgSrc) 
{ 
    lock(&mutex); 
    delete bgImage; 
    ++imageChanges; 
    bgImage = new Image(imgSrc); 
    unlock(&mutex); 
}

2. 異常安全條件

  • 不泄漏任何資源:若new Image(imgSrc)異常,則unlock永不解鎖
  • 不容許數據破壞:若new Image(imgSrc)異常,則bgImage指向被刪除的指針,且imageChanges已被修改,致使未成功執行卻修改了數據。

3. 對象管理資源:解決資源泄漏

void PrettyMenu::changeBackground(std::istream& imgSrc) 
{ 
    Lock ml(&mutex);//來自條款14; 
    delete bgImage; 
    ++imageChanges; 
    bgImage = new Image(imgSrc); 
}

4. 異常安全函數保證

  • 基本承諾:異常拋出時,保持有效狀態,沒有對象或數據結構被破壞
  • 強烈保證:異常出現時,程序狀態不改變,成功則徹底成功,失敗則會到以前狀態
  • 不拋擲(nothrow)保證:承諾不拋出異常

5. 基本承諾

class PrettyMenu{ 
    ... 
    std::tr1::shared_ptr<Image> bgImage; 
    ... 
};

void PrettyMenu::changeBackground(std::istream& imgSrc) 
{ 
    Lock ml(&mutex); 
    bgImage.reset(new Image(imgSrc)); 
    ++imageChanges; 
}

6. 強烈保證:copy and swap

struct PMImpl{ 
    std::tr1::shared_ptr<Image> bgImage; 
    int imageChanges; 
}; 
class PrettyMenu{ 
    ... 
private: 
    Mutex mutex; 
    std::tr1::shared_ptr<PMImpl> pImpl; 
}; 
void PrettyMenu::changeBackground(std::istream& imgSrc) 
{ 
    using std::swap; 
    Lock ml(&mutex); 
    std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl)); 
    pNew->bgImage.reset(new Image(imgSrc)); //修改副本 
    ++pNew->imageChanges; 
    swap(pImpl, pNew);//置換數據 
}
相關文章
相關標籤/搜索