在栈/堆上生成对象
c++中,有时我们希望某种类型的对象有“自我析构”的能力,即能够"delete this",这样就要求该类型的对象被分配于堆中。另外还可能在某些场景下必须保证某一类型绝不会发生内存泄漏,即需要没有任何一个该类型的对象从堆中分配出来。
在堆中生成对象
我们知道非堆对象会在其定义点自动构造,并在其寿命结束时自动析构,所以要保证对象在堆中生成,只要让那些被隐式调用的构造函数和析构函数不合法就可以了。
更具体来说,最直接的方法是将构造函数和析构函数都声明为private,但由于一个类可能有许多个构造函数,其中包括copy constructor,以及default constructor,类的作者必须记住将他们都每一个都声明为private,这样比较麻烦。更简单的方法是使析构函数为private,而构造函数仍为public。例如,heap-based 类:
class HeapBased
{
public:
HeapBased(){m_value = 0;}
HeapBased(int value);
HeapBased(const HeapBased& rhs);
void destroy()const
{
delete this;
}
private:
~HeapBased(); //将dtor声明为private
private:
int m_value;
};
生成对象的操作:
HeapBased implicitObj; //隐式调用ctor,在对象的dtor稍后被隐式调用后会出错
HeapBased* pHeadBased = new HeapBased(); //succ
...
delete pHeadBased; //error! 试图调用private dtor,
pHeadBased->destroy(); //succ
但是还有一点需要考虑的,就是在存在继承和包含关系时,private dtor 会导致派生类出错。那么我们就需要在存在继承关系时,令析构函数为protected,而在存在包含关系时,将内含HeapBased对象变为包含一个指向HeapBased对象的指针。
class HeapBased
{
public:
HeapBased(){m_value = 0;}
HeapBased(int value);
HeapBased(const HeapBased& rhs);
void destroy()const
{
delete this;
}
protected:
~HeapBased(); //将dtor声明为private
private:
int m_value;
};
class DerivedHeapBased : public HeapBased //可以正常取用protected members
{
...
};
class ContainHeadpBased
{
...
private:
HeapBased* m_heapBased;
};
禁止对象生成于heap内
想要阻止将对象在堆内生成的操作,由于这些对象总是以new产生出来,我们可以让调用new的操作不合法。虽然我们不能够影响new operator 的能力(由语言内建),但是我们可以利用 new operator 总是调用 operator new 的原则,而operator new 是我们可以自行声明的。即我们可以将其声明为private。
例如,对不不希望将对象生成于heap 内的场景:
class NoneHeap
{
private:
static void* operator new(size_t size);
static void operator delete(void *ptr);
};
使用该类时:
NoneHeap pNoneHeap; //succ
static NoneHeap pNoneHeap2; //succ
NoneHeap* pNoneHeap3 = new NoneHeap();//error! 企图调用private operator new
除此之外,如果也需要禁止 由NoneHeap对象所组成的数组在堆内生成,可以将 operator new[] 和 operator delete[]也声明为 private。
而对于存在继承和包含关系的场景,由于 operator new 和 operator delete 都会被继承,所有派生类如果另外没有声明这些函数为public,那么便会继承这两个函数的private版本,即与父类的表现一致。