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就好了。

【M27】要求或者禁止对象产生于heap之中的更多相关文章

  1. MoreEffectiveC++Item35 条款27: 要求或禁止对象产生于heap中

    一 要求对象产生在heap中 阻止对象产生产生在non-heap中最简单的方法是将其构造或析构函数声明在private下,用一个public的函数去调用起构造和析构函数 class UPNumber ...

  2. 《MORE EFFECTIVE C++》条款27 要求或者禁止对象分配在堆上

    1. 要求对象分配在堆上 临时对象一般是存在于栈中的,或者是静态对象存在于常量存储区的.那么当创建一个这样的对象的时候,一般是需要隐式或显式地调用构造函数,在销毁的时候调用析构函数的.可以从这方面入手 ...

  3. C++如何禁止对象的复制操作

    最容易想到的是将拷贝构造函数与赋值函数声明为private.但是,private只是说外部不能直接调用,但是可以间接通过类的成员函数与友元函数对其访问.那么怎么办呢? ---->在类中,允许声明 ...

  4. 将一个对象push到数组之中的几点问题

    在项目开发中我们需要向意数组中添加对象:首先想到的是利用数组的api,----push demo: var ar = [1,2,3] var ar2 = [11,22,33] var obj = { ...

  5. C++学习书籍推荐《More Effective C++》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <More Effective C++:35个改善编程与设计的有效方法(中文版)>:传世经典书丛 媒体推荐 <Effective c++&g ...

  6. More Effective C++: 05技术(25-28)

    25:将constructor 和 non-member functions 虚化 所谓 virtual constructor是某种函数,视其输入可产生不同类型的对象.比如下面的代码: class ...

  7. More Effective C++ 35 条款

    一.基础议题(basics) 条款1:仔细区别 pointers 和 references(Distinguish between pointers and references) 一个基本的语法问题 ...

  8. C++ new(2)

    1. new与operator new C++中有很多语法让人难以理解,如:new operator(操作符,下同)和operator new之间差异,确切的说,应该是new与operator new ...

  9. More Effective C++笔记(一)(精心整理)

    一.基础议题 条款1:仔细区别pointers和references 指针使用*和->,引用使用"." 引用必须指向一个已初始化的对象,不能为null,而指针可以指向某个对象 ...

随机推荐

  1. 【转载】HBase基本概念和hbase shell常用命令用法

    1. 简介 HBase是一个分布式的.面向列的开源数据库,源于google的一篇论文<bigtable:一个结构化数据的分布式存储系统>.HBase是Google Bigtable的开源实 ...

  2. testng之listener

    这周在给人培训selenium+testng框架时,讲到listener这块发现对listener并没有完全了解,于是自己又重新学习了下. 以下是 TestNG 提供的几种监听器: IAnnotati ...

  3. 【转】linux下mkisofs制作光盘映像cdrecord刻录光盘

    1.制作光盘映像文件 $mkisofs -R -o /var/tmp/oracle.iso /home/oracle $mkisofs -o myiso.iso /home/oracle/data 补 ...

  4. jquery图片裁切+PHP文件上传

    下载地址:download.csdn.net/source/2745353

  5. js代码大全

    超级实用且不花哨的js代码大全 事件源对象event.srcElement.tagNameevent.srcElement.type 捕获释放event.srcElement.setCapture() ...

  6. asp.net mvc源码分析-Action篇 IModelBinder

    我们首先还是看看ReflectedParameterBindingInfo的Binder属性吧: public override IModelBinder Binder {            ge ...

  7. VS常用技巧

    VS2005代码编辑器的展开和折叠代码确实很方便和实用.以下是展开代码和折叠代码所用到的快捷键,很常用: Ctrl + M + O: 折叠所有方法 Ctrl + M + M: 折叠或者展开当前方法 C ...

  8. Python学习第二天数组

    1:Python定义数组:a=[0,1,2,3,4] ;   打印数组list(a); 这时:a[0]=0, a[1]=1, a[[2]=2...... 1.1:如果想定义一个很长的数组可以用到pyt ...

  9. js运动 分享到

    <!doctype html> <html> <head> <meta charset = "utf-8"> <title&g ...

  10. jquery获取显示器,屏幕的宽度,和高度

    Javascript: 网页可见区域宽: document.body.clientWidth网页可见区域高: document.body.clientHeight网页可见区域宽: document.b ...