天天看點

[C++再學習系列] 深入new/delete:類域的operator new重載

為 class 重載 operator new 時必須定義為類的靜态函數 ( 預設為 static 函數 ) 。重載 operator new 更多的是為了提高程式效率,比如使用靜态記憶體代替動态配置設定,啟用小對象配置設定器等。但是要正确重載類域的 operator new 并不容易,有很多規則需要注意: 1) 總是成對提供 new/delete ; 2) 如重載 operator new 一定要同時提供标準形式的 new 。舉例:

class T {

   static void* operator new(std::size_t);

    static void* operator new(std::size_t, CustomAllocator&);

    static void operator delete(void*, std::size_t);

};

T* p = new(alloc) T;

上述代碼将被編譯器展成下述代碼 ( 猜測,如果有高人知道如何檢視編譯器生成的中間代碼,煩請告知)

// compiler-generated code for T* p = new(alloc) T;

//

void* __compilerTemp = T::operator new (sizeof(T), alloc);  // 1

T* p;

try {

  p = new (__compilerTemp) T;      // 2 // construct a T at address __compilerTemp

}

catch(...) {                        // constructor failed, attention here…

  T::operator delete (__compilerTemp, sizeof(T), alloc);  // 3

  throw;

       注釋 1 : operator new 用于配置設定記憶體, new 的第一步驟;

       注釋 2 : placement new 用于在于位址上建構對象,也就是調用 T 的構造函數。

       注釋 3 :與 operator new 配套的 operator delete 。

       C++ 标準規定:當且僅當 operator delete 的重載存在時,以上代碼才能生成。否則,在構造函數失敗的情況下,代碼不會調用 operator delete 。也就是說,如果構造函數抛異常,記憶體将洩漏。

這意味着:當提供 void* operator new(parms) 重載時,必須同時提供 void operator delete(void*, parms), 這裡參數清單的第一個參數總為 std::size_t 。 對于 operator new[] 也是如此。例外,對于 placement new 由于并不實際配置設定記憶體,可不重載相應的 operator delete 。

避免隐藏全局的operator new 和基類重定義的 operator new

       前面已經提到過 C++ 名字查找規則,對于重載的 operator new 也需要遵循此規則。當類中重載 operator new ,那麼全局的operator new 将被隐藏;如果派生類重載 operator new ,那麼基類的版本将被隐藏。由于 placement new 大量用于 STL 的優化中,故一定要避免隐藏 placement new 。隐藏 operator new 的這類錯誤編譯器會給出提示。 

       重載 opeartor new 并避免隐藏全局 operator new 的途徑:

       1) 對于基類重載的 operator new ,使用 using 來導入相應名字。

class C : public B {// …

public:

    static void* operator new(size_t, MemoryPool&); // private version

    using B::operator new;

       };

       2) 對一般重載 operator new 的類,除了提供私有版本外,應該對所有全局 operator new 形式提供轉換函數。如下:

class C {// …

static void* operator new(size_t, MemoryPool&);   // private version 

  static void* operator new(std::size_t s) {

  return ::operator new(s);        // global version

  }

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

  return ::operator new(s, nt);

  static void* operator new(std::size_t s, void* p) {

  return ::operator new(s, p);

相關文章:

<a href="http://www.cnblogs.com/zhenjing/archive/2011/01/archive/2011/01/10/3_kind_new.html">深入new/delete:New的3種形态</a>

<a href="http://www.cnblogs.com/zhenjing/archive/2011/01/archive/2011/01/10/groble_new.html">深入new/delete:Operator new的全局重載</a>

<a href="http://www.cnblogs.com/zhenjing/archive/2011/01/archive/2010/12/02/override_overwrite_overload.html">派生類函數的重實作規則(override-覆寫)</a>

---------------------------------------------------

歡迎轉載,請注明作者和出處

本文轉自 zhenjing 部落格園部落格,原文連結:http://www.cnblogs.com/zhenjing/archive/2011/01/17/class_new.html  ,如需轉載請自行聯系原作者