【M27】要求或者禁止对象产生于heap之中

1、要求对象只能产生于heap之中,该怎么办?

  栈上的对象肯定调用构造方法和析构方法(离开作用域的时候),因此,要求对象只能产生于heap之中,也就是禁止栈上产生对象,解决办法有两种:将所有的构造方法声明为private,或者将析构方法声明为private。

2、将所有的构造方法声明为private,这样就不能在栈上构造对象了。这有两点需要注意:

  a、这种情况下,不能在外部使用new operator在堆上构造对象,因为new operator要在分配的内存上,调用构造方法构造对象。因此,需要重新暴露接口,返回堆上的对象。办法有:在类内部使用new operator,暴露static方法;使用友元方法或者友元类。

  b、一个类往往有多个构造方法,必须将所有的构造方法都声明为private。对于default 构造方法,如果没有声明任何构造方法,编译器会自动生成一个。对于copy构造,没有声明,编译器也会自动生成一个。

3、将析构方法声明为private,由于栈对象离开作用域,会自动调用析构方法,出现错误,在编译时就报错。这有两点需要注意:

  a、这种情况下,不能在外部使用delete operator删除指针,因为delete operator要调用析构方法,然后调用operator delete释放内存。因此,需要重新暴露接口,Destroy方法,在Destroy方法内部调用delete operator。

  b、相比于构造方法,析构方法只有一个,只需要将这一个析构方法声明为private就好了。

4、需要注意,将构造方法或者析构方法声明为private,将导致两个问题,那就是继承和内含,这两种情况都要调用构造方法和析构方法。

  对于继承,可以将父类的构造方法和析构方法放大访问权限,为protected。

  对于内含一个对象,修改为内含一个指针,指向对象。使用其他暴露的借口,获取堆上的对象和释放内存(Destroy)。

5、考虑下面的问题,如何判断某个对象是否位于heap内?

6、我们知道,在堆上创建对象必定调用operator new分配内存,因此,可以在operator new调用的时候,标识将要产生的对象在堆上,对象构造后,然后清除标识。这有两个问题:a、对于数组,使用operator new[],一次性分配多个内存,只有第一个对象是分配在堆上。b、考虑new UPNumber(* new UPNumber),C++的执行顺序可能是先调用两次operator new,在调用两次构造方法,导致上述的办法失效。

7、C++程序的内存布局,从高到低以此为stack,heap,静态存储区,stack向下增长,heap向上增长。在栈上创建一个对象,如果目标对象在栈上,新建的对象地址,肯定小于目标对象的地址。因此,新建对象的地址小于目标对象的地址,说明目标对象在栈上,否则在堆上。这里有个小问题,目标对象也可能在静态存储区。另外,这种做法不具有移植性,有些系统的内存布局不是上面的情况。

8、判断对象是否在堆上,很难办。思考下,我们为什么要判断对象是否在堆上?真实的需求是,判断执行delete是否安全。那怎么办呢?

  对于分配获取的指针,放到一个集合,delete指针的时候,判断指针是否在集合,如果在集合,执行delete就是安全的,否则不安全。

9、如何禁止对象产生于heap之中?

  这个很简单,在堆上创建对象,必定调用operator new分配内存,因此将operator new声明为private就好了。

posted on 2014-04-02 20:17  Andy Niu  阅读(682)  评论(0编辑  收藏  举报