更多 C++ 习语/具体数据类型
外观
通过允许或禁止使用自由存储(堆)进行动态分配来控制对象的范围和生命周期
本节内容为空。请通过 扩展它 来帮助我们。 |
C++ 提供了两种方法来控制对象的生存期并将其绑定到程序级标识符(变量)。第一种是作用域变量和对象,它们在作用域结束后立即被销毁(例如,函数作用域中的整数)。第二种是作用域变量(通常是指针)和自由存储中动态分配的对象。在这种情况下,在变量作用域结束时,变量将不再存在,但对象的生存期将继续(例如,单例、窗口对象)。可以使用具体数据类型习语强制选择对象生存期的第一种方式或第二种方式。
此习语简单地使用类级访问修饰符(private、protected)来实现目标。以下代码展示了 MouseEventHandler 类如何强制动态分配。
class EventHandler
{
public:
virtual ~EventHandler () {}
};
class MouseEventHandler : public EventHandler // Note inheritance
{
protected:
~MouseEventHandler () {} // A protected virtual destructor.
public:
MouseEventHandler () {} // Public Constructor.
};
int main (void)
{
MouseEventHandler m; // A scoped variable is not allowed as destructor is protected.
EventHandler *e = new MouseEventHandler (); // Dynamic allocation is allowed
delete e; // Polymorphic delete. Does not leak memory.
}
强制动态分配的另一种方法是阻止对构造函数的直接访问,而是提供一个静态函数 instance() 来返回一个动态分配的对象。它在许多方面类似于单例设计模式。此外,严格来说,使用多态删除来回收内存并不是必需的。一个成员函数 destroy() 可以达到这个目的,从而节省了用于 v-table 指针的空间。
class MouseEventHandler // Note no inheritance
{
protected:
MouseEventHandler () {} // Protected Constructor.
~MouseEventHandler () {} // A protected, non-virtual destructor.
public:
static MouseEventHandler * instance () { return new MouseEventHandler(); }
void destroy () { delete this; } // Reclaim memory.
};
此习语的另一个极端是强制使用作用域变量(又称自动变量)。这可以通过使用私有 new 运算符来实现。
class ScopedLock
{
private:
static void * operator new (size_t size); // Disallow dynamic allocation
static void * operator new (size_t, void * mem); // Disallow placement new as well.
};
int main (void)
{
ScopedLock s; // Allowed
ScopedLock * sl = new ScopedLock (); // Standard new and nothrow new are not allowed.
void * buf = ::operator new (sizeof (ScopedLock));
ScopedLock * s2 = new(buf) ScopedLock; // Placement new is also not allowed
}
ScopedLock 对象不能使用 new 运算符、nothrow new 运算符和 placement new 运算符进行动态分配。
- 具体数据类型 - J. Coplien。