一般情况下,编写一个类,是可以在栈或者堆分配空间。但有些时候,你想编写一个只能在栈或者只能在堆上面分配空间的类。这能不能实现呢?仔细想想,其实也是可以滴。

在C++中,类的对象建立分为两种,一种是静态建立,如A a;另一种是动态建立,如A* ptr=new A;这两种方式是有区别的。

1、静态建立类对象:是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数。

2、动态建立类对象,是使用new运算符将对象建立在堆空间中。这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配;第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。

那么如何限制类对象只能在堆或者栈上建立呢?下面分别进行讨论。

1、只能在堆上分配类对象,就是不能静态建立类对象,即不能直接调用类的构造函数。

容易想到将构造函数设为私有。在构造函数私有之后,无法在类外部调用构造函数来构造类对象,只能使用new运算符来建立对象。然而,前面已经说过,new运算符的执行过程分为两步,C++提供new运算符的重载,其实是只允许重载operator new()函数,而operatornew()函数只用于分配内存,无法提供构造功能。因此,这种方法不可以。

当对象建立在栈上面时,是由编译器分配内存空间的,调用构造函数来构造栈对象。当对象使用完后,编译器会调用析构函数来释放栈对象所占的空间。编译器管理了对象的整个生命周期。如果编译器无法调用类的析构函数,情况会是怎样的呢?比如,类的析构函数是私有的,编译器无法调用析构函数来释放内存。所以,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈上了。代码如下:

[cpp] view plaincopy
  1. class A
  2. {
  3. public:
  4. A(){}
  5. void destory(){delete this;}
  6. private:
  7. ~A(){}
  8. };

试着使用A a;来建立对象,编译报错,提示析构函数无法访问。这样就只能使用new操作符来建立对象,构造函数是公有的,可以直接调用。类中必须提供一个destory函数,来进行内存空间的释放。类对象使用完成后,必须调用destory函数。

上述方法的缺点:

 一、无法解决继承问题。如果A作为其它类的基类,则析构函数通常要设为virtual,然后在子类重写,以实现多态。因此析构函数不能设为private。还好C++提供了第三种访问控制,protected。将析构函数设为protected可以有效解决这个问题,类外无法访问protected成员,子类则可以访问。

二、类的使用很不方便,使用new建立对象,却使用destory函数释放对象,而不是使用delete。(使用delete会报错,因为delete对象的指针,会调用对象的析构函数,而析构函数类外不可访问)这种使用方式比较怪异。为了统一,可以将构造函数设为protected,然后提供一个public的static函数来完成构造,这样不使用new,而是使用一个函数来构造,使用一个函数来析构。代码如下,类似于单例模式

[cpp] view plaincopy
  1. class A
  2. {
  3. protected:
  4. A(){}
  5. ~A(){}
  6. public:
  7. static A* create()
  8. {
  9. return new A();
  10. }
  11. void destory()
  12. {
  13. delete this;
  14. }
  15. };

这样,调用create()函数在堆上创建类A对象,调用destory()函数释放内存。

2、只能在栈上分配类对象

只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。虽然你不能影响new operator的能力(因为那是C++语言内建的),但是你可以利用一个事实:new operator 总是先调用 operator new,而后者我们是可以自行声明重写的。因此,将operator new()设为私有即可禁止对象被new在堆上。代码如下:

[cpp] view plaincopy
  1. class A
  2. {
  3. private:
  4. void* operator new(size_t t){}     // 注意函数的第一个参数和返回值都是固定的
  5. void operator delete(void* ptr){} // 重载了new就需要重载delete
  6. public:
  7. A(){}
  8. ~A(){}
  9. };

参考:

1、http://blog.csdn.net/g5dsk/article/details/4775144

2、http://www.cnblogs.com/h2-database/archive/2012/06/28/2572497.html

转载于:https://www.cnblogs.com/dsdr/p/6092659.html

[转载]如何限制一个类对象只在栈(堆)上分配空间?相关推荐

  1. Java对象都是在堆上分配空间吗?答案竟然是...

    作者 l Hollis 来源 l Hollis(ID:hollischuang) Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或 ...

  2. Java 对象都是在堆上分配内存吗?

    为了防止歧义,可以换个说法:Java对象实例和数组元素都是在堆上分配内存的吗? 答:不一定.满足特定条件时,它们可以在(虚拟机)栈上分配内存. JVM内存结构很重要,多多复习 这和我们平时的理解可能有 ...

  3. java 堆_Java 对象都是在堆上分配内存吗?

    为了防止歧义,可以换个说法:Java对象实例和数组元素都是在堆上分配内存的吗? 答:不一定.满足特定条件时,它们可以在(虚拟机)栈上分配内存. JVM内存结构很重要,多多复习 这和我们平时的理解可能有 ...

  4. 如何让类对象只在栈(堆)上分配空间?(转)

    参考:http://blog.csdn.net/hxz_qlh/article/details/13135433 只在堆上分配:将析构函数设为私有: 只在栈上分配:将operator new设为私有. ...

  5. 如何限制对象只能建立在堆上或者栈上

    转自http://blog.csdn.net/szchtx/article/details/12000867# 在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* p ...

  6. 对象并不一定都是在堆上分配内存的

    JVM内存分配策略 关于JVM的内存结构及内存分配方式,不是本文的重点,这里只做简单回顾.以下是我们知道的一些常识: 1.根据Java虚拟机规范,Java虚拟机所管理的内存包括方法区.虚拟机栈.本地方 ...

  7. 求你了,别再说Java对象都是在堆内存上分配空间的了!

    Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解.可以说,关于JVM的相关知识,基本是每个Java开发者 ...

  8. ndarray 与 array 的区别 关系,所以ndarray是一个类对象,而array是一个方法

    ndarray 与 array 的区别 关系 置顶 wanglll* 2020-02-06 20:00:37  8455  已收藏 17 分类专栏: 数据分析 文章标签: numpy 版权 ndarr ...

  9. 【C++学习】对私有构造析构函数的思考:new一个类对象vs直接创建类对象

    前置知识: new的类对象需要手动delete.且使用堆空间.且只能用指针接收. 直接创建的类对象创建在栈中(或说堆栈).不需要手动delete,随着生存周期的结束(如所在的函数return了)而释放 ...

最新文章

  1. react中使用scss_我如何将CSS模块和SCSS集成到我的React应用程序中
  2. 【从单体架构到分布式架构】(二)请求增多,单点变集群(1):负载均衡
  3. Android网络传输中必用的两个加密算法:MD5 和 RSA (附java完成测试代码)
  4. 深入理解Fabric环境搭建的详细过程
  5. js 字符串截取 获取固定标识字段
  6. String、StringBuffer 、StringBuilder 的区别(转)
  7. 22Exchange Server 2010跨站点部署-邮件流测试及重定向
  8. 值得收藏的前端大牛博客
  9. Android LED电子表时钟字体digital font
  10. python实现文件管理系统_Python - 文件管理系统
  11. 涨点神器!特征金字塔技术总结
  12. 世界著名汽车标志(大全)
  13. cmake出错:Building inplace are not allowed. You should create a separate directory for Building.
  14. 第十三天-Http-GET、POST
  15. 6款超实用微信小程序,任何手机都需要!
  16. org.springframework.web.client.HttpServerErrorException
  17. less与sass的区别
  18. 前端、框架和其他(155题)
  19. opencv安装实录附十几行C++实现的一个人脸识别demo
  20. ASP.NET Core 快速入门

热门文章

  1. 编译后错误提示为pls-00103:出现符号在需要下列之一时:begin case declare
  2. 第九节--绑定 -- Classes and Objects in PHP5 [9](转)
  3. MSDN WebCast网站全新改版
  4. 非常时期,手机不能没电不能离身啊
  5. 灵活、轻便,阿里开源简化GNN应用框架Graph-Learn
  6. TensorFlow2.1正式版发布!最后一次支持Python2,进一步支持TPU
  7. 【OpenCV】OpenCV函数精讲之 -- Mat和IplImage之间的相互装换(OpenCV2.0和OpenCV3.0)
  8. BBAug: PyTorch的物体检测包
  9. 阿里达摩院发布2019十大科技趋势!AI专用芯片将挑战GPU的绝对统治地位
  10. python导入requests库一直报错原因总结_python pip 安装库文件报错:pip install ImportError: No module named _internal...