閱讀242 返回首頁    go 阿裏雲 go 技術社區[雲棲]


C++編程規範指46:如果提供專門的new,應該提供所有標準形式(普通、就地和不拋出)

摘要:

    不要隱藏好的new:如果類定義了operatornew 的重載,就應該提供operator new 所有三種形式——普通(plain)、就地(in-place)和不拋出(nothrow)的重載。

    很少需要提供自定義的new 或者delete,但是如果確實需要,通常也不想隱藏內置的簽名。

C++中,在某個作用域(比如一個類作用域)裏定義了一個名字之後,就會隱藏所有外圍作用域中(如,在基類或者外圍名字空間)同樣的名字,而且永遠不會發生跨作用域的重載。當上述名字是operator new時,需要特別小心,以免對類的客戶產生不良影響。

    假設我們定義了一個類專門的operatornew:

Class C

{

         //……

         Static void* operatornew(size_t,void*);//隱藏三種常規形式

};

    然後,如果有人試圖編寫一個和普通舊式newC一樣無趣的表達式,編譯器會拒絕對其進行編譯,其根據是無法找到普通舊式的operator new。生命接受一個memorypool為參數的C::operator new重載,將隱藏所有其他重載,包括我們都熟知而且愛用的內置全局版本,也就是:

Void* operatornew(std::size_t);//普通new

Void* operatornew(std::size_t,std::nothrow_t) throw();//不拋出new

Void* operatornew(std::size_t,void*);//就地new

    或者,類也可能對以上三種operatornew 之一提供自己專用的版本。在此情況下,如果聲明了其中之一,默認時類將屏幕其他兩個:

Class C

{

         //……

         Static void* operatornew(size_t,void*);//隱藏其他兩種常規形式

};

    應該讓類C在作用域中顯式地聲明operatornew 的所有三種標準變體。通常,所有三種形式都有相同的可見性。(各個形式還可以將可見性設為private,比如要顯示地禁用普通或者不拋出operator new,但是本條款的目的是提醒讀著記住不要因為疏忽而隱藏它們。)

    請注意,應該總是避免就地new,因為它在STL容器中有廣泛的使用。

    最後一個技巧是:在兩種不同的環境下,公開已隱藏的operator new需要采用來年各種不同的方式。如果類的基類也定義了operator new,那麼要公開operator new所需做的就是:

Class C:public B

{

         //……

         Public:

         Using B::operator new;

};

    否則,如果沒有基類版本或者基類沒有定義operatornew,就需要寫一些短小的轉送函數(因為無法通過using從全局名字空間中導入名字):

Class C

{

         //……

         Public:

         Static void* operator new(std::size_t s)

         {

                   Return ::operator new(s);

}

Static void* operator new(std::size_t s,std::nothrow_t nt) throw()

{

         Return ::operator new(s,p);

}

};

    上麵的建議也適用於數組形式的operatornew[]和operator delete[]。

    避免在客戶代碼中國調用new(nothrow)版本,但是仍然要為客戶提供,以免客戶一旦要用到時感到奇怪。

最後更新:2017-04-03 12:55:10

  上一篇:go static class 和 static interface
  下一篇:go FFMPEG SDK 開發介紹