跳转到内容

更多 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,否则该类将继承其基类中声明的受保护的/私有的版本,从而阻止动态分配。

已知用法

[编辑 | 编辑源代码]
[编辑 | 编辑源代码]

参考文献

[编辑 | 编辑源代码]
华夏公益教科书