跳轉到內容

更多 C++ 慣用法/要求或禁止基於堆的物件

來自 Wikibooks,開放世界中的開放書籍

要求或禁止基於堆的物件

[編輯 | 編輯原始碼]
  • 要求或阻止在堆上建立物件

也稱為

[編輯 | 編輯原始碼]

C++ 支援不同的建立物件的方式:基於堆疊的(包括臨時物件)、基於堆的以及具有靜態儲存期的物件(例如,全域性物件、名稱空間範圍內的物件)。有時限制類物件的建立方式會很有用。例如,框架可能要求使用者僅建立基於堆的物件,以便它可以控制物件的生存期,而不管建立這些物件的函式是什麼。同樣,禁止在堆上建立物件也很有用。C++ 有慣用的方法來實現這一點。

解決方案和示例程式碼

[編輯 | 編輯原始碼]

要求基於堆的物件

在這種情況下,程式設計師必須使用 new 建立物件並禁止基於堆疊的物件和具有靜態儲存期的物件。其想法是阻止訪問始終用於基於堆疊物件的函式之一:建構函式或解構函式。阻止訪問建構函式,即受保護的/私有的建構函式,也會阻止基於堆的物件。因此,唯一可用的方法是建立一個受保護的解構函式,如下所示。請注意,受保護的解構函式也會阻止全域性和名稱空間範圍內的物件,因為這些物件最終會被銷燬,但解構函式是不可訪問的。同樣,這也適用於臨時物件,因為銷燬臨時物件需要一個公共解構函式。

class HeapOnly {
  public:
    HeapOnly() {} 
    void destroy() const { delete this; }
  protected:
    ~HeapOnly() {}
};
HeapOnly h1;     // Destructor is protected so h1 can't be created globally
HeapOnly func()  // Compiler error because destructor of temporary is protected
{
  HeapOnly *hoptr = new HeapOnly; // This is ok. No destructor is invoked automatically for heap-based objects
  return *hoptr;
}
int main(void) {
  HeapOnly h2; // Destructor is protected so h2 can't be created on stack
}

受保護的解構函式還阻止訪問 delete HeapOnly,因為它內部呼叫了解構函式。為了防止記憶體洩漏,提供了 destroy 成員函式,它在自身上呼叫 delete。派生類可以訪問受保護的解構函式,因此 HeapOnly 類仍然可以作為基類使用。但是,派生類不再具有相同的限制。

禁止基於堆的物件

可以透過禁止訪問所有形式的特定於類的 new 運算子來阻止物件的動態分配。標量物件的 new 運算子和物件陣列的 new 運算子是兩種可能的變體。兩者都應宣告為受保護的(或私有的),以防止基於堆的物件。


class NoHeap {
protected:
  static void * operator new(std::size_t);      // #1: To prevent allocation of scalar objects
  static void * operator new [] (std::size_t);  // #2: To prevent allocation of array of objects
};
class NoHeapTwo : public NoHeap {
};
int main(void) {
  new NoHeap;        // Not allowed because of #1
  new NoHeap[1];     // Not allowed because of #2
  new NoHeapTwo[10];  // Not allowed because of inherited protected new operator (#2).
}

上述受保護的 new 運算子宣告阻止了剩餘的編譯器生成的版本,例如放置 new 和 nothrow new。僅將標量 new 宣告為受保護的是不夠的,因為它仍然可以執行 new NoHeap[1]。受保護的 new [] 運算子阻止了所有大小(包括大小為 1)的陣列的動態分配。

限制對 new 運算子的訪問還阻止派生類使用動態記憶體分配,因為 new 運算子和 delete 運算子是繼承的。除非這些函式在派生類中被宣告為 public,否則該類將繼承其基類中宣告的受保護的/私有的版本,從而阻止動態分配。

已知用法

[編輯 | 編輯原始碼]
[編輯 | 編輯原始碼]

參考文獻

[編輯 | 編輯原始碼]
華夏公益教科書