首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

Effective C++ 條款 52:寫了 placement new 也要寫 placement delete

     編輯:C++ 入門

Effective C++ 條款 52:Placement New/Delete 配對原則

當重載帶額外參數的 operator new(placement new)時,必須提供對應參數完全一致的 operator delete(placement delete),否則構造函數拋異常會導致內存洩漏。

問題根源

Widget* pw = new Widget; 調用 operator new 分配內存,再調用構造函數。若構造拋異常,運行時自動調用對應的 operator delete 釋放內存。標準 new/delete 簽名固定,編譯器知道調用哪個。但 placement new 簽名任意(如 operator new(size_t, ostream&)),運行時無法推導對應的 delete,若缺少 placement delete,則不釋放內存 → 洩漏。

正確做法

class Widget {
public:
    static void* operator new(size_t size, ostream& log) { /* 記錄日誌並分配 */ }
    static void operator delete(void* p, size_t size) { ::operator delete(p); } // 普通 delete
    static void operator delete(void* p, ostream& log) { ::operator delete(p); } // 必須有的 placement delete
};

若構造拋異常,operator delete(void*, ostream&) 會被調用。普通 delete pw; 仍調用普通 delete,不影響。

遮蔽問題與解決方案

類內聲明任何 operator new 會遮蔽全局/基類的所有 new(包括標準版)。導致客戶無法使用 new Widget。解決:建立基類 StandardNewDeleteForms 定義標準 new/delete,派生類用 using 引入:

class StandardNewDeleteForms {
public:
    static void* operator new(size_t sz) { return ::operator new(sz); }
    static void operator delete(void* p) { ::operator delete(p); }
    static void* operator new(size_t sz, void* p) { return ::operator new(sz, p); }
    static void operator delete(void* p, void*) { ::operator delete(p); }
    static void* operator new(size_t sz, const nothrow_t&) { return ::operator new(sz, nothrow); }
    static void operator delete(void* p, const nothrow_t&) { ::operator delete(p); }
};

class Widget : public StandardNewDeleteForms {
public:
    using StandardNewDeleteForms::operator new;
    using StandardNewDeleteForms::operator delete;
    static void* operator new(size_t, ostream&);
    static void operator delete(void*, ostream&);
};

核心準則

  1. 每個 placement new 必須配套同參數的 placement delete。
  2. 用基類 + using 保留標準 new/delete,避免遮蔽。
  3. placement delete 僅在「配套 placement new 的構造函數拋異常」時調用,普通 delete 永不調用它。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved