27要求(或禁止)对象产生于heap之中:
有时候,我们要求该类型的对象被分配与heap内,能够“delete this”;另一些时候,我们要求拥有某种确定性,保证某一些类型绝不会发生内存泄漏,原因是没有任何一个该类型的对象从heap中分配出来。
1、要求对象只能产生于heap之中,该怎么办?
栈上的对象肯定调用构造方法和析构方法(离开作用域的时候),因此,要求对象只能产生于heap之中,也就是禁止栈上产生对象,解决办法有两种:将所有的构造方法声明为private,或者将析构方法声明为private。
1) 将所有的构造方法声明为private,这样就不能在栈上构造对象了。这有两点需要注意:
a、这种情况下,不能在外部使用new operator在堆上构造对象,因为new operator要在分配的内存上,调用构造方法构造对象。因此,需要重新暴露接口,返回堆上的对象。办法有:在类内部使用new operator,暴露static方法;使用友元方法或者友元类。
b、一个类往往有多个构造方法,必须将所有的构造方法都声明为private。对于default 构造方法,如果没有声明任何构造方法,编译器会自动生成一个。对于copy构造,没有声明,编译器也会自动生成一个。
2) 将析构方法声明为private,由于栈对象离开作用域,会自动调用析构方法,出现错误,在编译时就报错。这有两点需要注意:
a、这种情况下,不能在外部使用delete operator删除指针,因为delete operator要调用析构方法,然后调用operator delete释放内存。因此,需要重新暴露接口,Destroy方法,在Destroy方法内部调用delete operator,由于Destroy是类内的方法,因此可以调用析构函数。
b、相比于构造方法,析构方法只有一个,只需要将这一个析构方法声明为private就好了。
2、需要注意,将构造方法或者析构方法声明为private,将导致两个问题,那就是继承和内含,这两种情况都要调用构造方法和析构方法。
对于继承,可以将父类的构造方法和析构方法放大访问权限,为protected。
对于内含一个对象,修改为内含一个指针,指向对象。使用其他暴露的借口,获取堆上的对象和释放内存(Destroy)。
具体使用:
要求对象产生于heap中,意思是需要阻止clients不得使用new以外的方法产生对象。比较好的方法就是将destructor定义为private,因为constructor的类型太多,所以仍然将constructor定义为public。然后定义一个pseudo destructor来调用真正的destructor。示例如下:
class HeapBasedObject
{
public:
HeapBasedObject() {}
void destroy() const { delete this; } // pseudo destructor
private:
~HeapBasedObject()noexcept {}
};
int main()
{
//HeapBasedObject h; 在栈上创建对象,错误
HeapBasedObject *ph = new HeapBasedObject;
//delete ph; 企图访问private析构函数,错误
ph->destroy();
}
3、禁止对象产生于heap之中,该怎么办?
禁止对象产生于heap中,则是要让clients不能使用new方法来产生对象。方法就是将operator new和operator delete定义为private。示例如下:
class NoHeapBasedObject
{
public:
NoHeapBasedObject() {}
~NoHeapBasedObject() {}
private:
static void *operator new(size_t size) {} //重载并定义为private
static void operator delete(void *ptr) {} //重载并定义为private
};
int main()
{
NoHeapBasedObject nh;
static NoHeapBasedObject snh;
//NoHeapBasedObject *pnh = new NoHeapBasedObject(); 错误
}
Comments NOTHING