【52】寫了placement new也要寫placement delete

Andy Niu發表於2014-01-24

1、Widget* pw = new Widget; 呼叫了兩個方法:第一個方法是operator new 負責分配記憶體;第二個方法是在分配的記憶體上構造Widget,即呼叫Widget的default構造方法。

2、那麼問題來了,如果operator new分配記憶體成功,而Widget構造丟擲異常,這種情況下,pw還沒有賦值,這不就導致資源洩露了?

  不會造成資源洩露,因為C++執行系統保證呼叫delete釋放資源。

3、正常的operator new 如下:

  void* operator new(std::size_t) throw (std::bad_alloc);

  正常的operator delete如下:

  void operator delete (void* rawMemory) throw(); // global作用域中的正常簽名式

  void operator delete (void* rawMemory,std::size_t size) throw (); //class 作用域中典型的簽名式

  除了上面的operator new,還有過載operator new,這些過載的new稱為placement new,其中有一個比較特殊的,如下:

  void* operator new (std::size_t, void* pMemory) throw ();

  當我們使用new在堆上申請記憶體時,編譯器嘗試找到一塊記憶體。而上面的placement new是說,不要去找記憶體了,直接分配在pMemory上。

4、現在問題來了,存在多個過載的operator new,當我們呼叫一個過載的new,出現上面的情況,即構造Widget出現異常,執行時該呼叫哪個delete呢?

  做法是:呼叫一個與operator new 對應的operator delete,如果沒有這樣的delete,那麼執行時系統什麼也不做。這就必然導致資源洩漏。因此,為了避免這種情況下,使用者必須保證operator new 存在與它對應的operator delete。

5、上面delete的呼叫,是說,使用operator new,構造物件時出現異常,執行期系統呼叫與之對應的operator delete。正常情況下,delete pw呼叫正常的delete。

6、為了避免漏掉相關的delete,可以建立一個父類,其它類繼承,共享這些方法。需要注意的是,繼承會導致掩蓋同名稱的成員,因此需要在子類中使用using XXX。

相關文章