C 堆对象如何禁用
创始人
2024-06-22 14:40:12
0

C++中对于内存的相关知识是一个比较重要而且复杂的知识点,我们需要不断的深入的对其进行研究。今天在这里我们将会针对C++堆对象的一些应用方法做一个详细的介绍,应该可以帮助大家对此有一个深刻的认识。#t#

产生C++堆对象的方法是使用new操作,如果我们禁止使用new不就行了么。再进一步,new操作执行时会调用operator new,而operator new是可以重载的。方法有了,就是使new operator 为private,为了对称,最好将operator delete也重载为private。

现在,你也许又有疑问了,难道创建栈对象不需要调用new吗?是的,不需要,因为创建栈对象不需要搜索内存,而是直接调整堆栈指针,将对象压栈,而operator new的主要任务是搜索合适的堆内存,为C++堆对象分配空间,这在上面已经提到过了。好,让我们看看下面的示例代码:

  1. #include stdlib.h 需要用到C式内存分配函数   
  2. class Resource ; 代表需要被封装的资源类   
  3. class NoHashObject   
  4. {   
  5.  private   
  6.   Resource ptr ;指向被封装的资源   
  7.   ... ... 其它数据成员   
  8.   void operator new(size_t size) 非严格实现,仅作示意之用   
  9.   {   
  10.    return malloc(size) ;   
  11.   }   
  12.   void operator delete(void pp) 非严格实现,仅作示意之用   
  13.   {   
  14.    free(pp) ;   
  15.   }   
  16.  public   
  17.   NoHashObject()   
  18.   {   
  19.    此处可以获得需要封装的资源,并让ptr指针指向该资源   
  20.    ptr = new Resource() ;   
  21.   }   
  22.   ~NoHashObject()   
  23.   {   
  24.    delete ptr ; 释放封装的资源   
  25.   }   
  26. }; 

NoHashObject现在就是一个禁止C++堆对象的类了,如果你写下如下代码:

  1. NoHashObject fp = new NoHashObject() ; 编译期错误!   
  2. delete fp ;  

上面代码会产生编译期错误。好了,现在你已经知道了如何设计一个禁止堆对象的类了,你也许和我一样有这样的疑问,难道在类NoHashObject的定义不能改变的情况下,就一定不能产生该类型的C++堆对象了吗?不,还是有办法的,我称之为“暴力破解法”。C++是如此地强大,强大到你可以用它做你想做的任何事情。这里主要用到的是技巧是指针类型的强制转换。

  1. void main(void)   
  2. {   
  3. char temp = new char[sizeof(NoHashObject)] ; 

 

强制类型转换,现在ptr是一个指向NoHashObject对象的指针

  1. NoHashObject obj_ptr = (NoHashObject)temp ;  

temp = NULL ; 防止通过temp指针修改NoHashObject对象

再一次强制类型转换,让rp指针指向堆中NoHashObject对象的ptr成员

  1. Resource rp = (Resource)obj_ptr ;  

初始化obj_ptr指向的NoHashObject对象的ptr成员

  1. rp = new Resource() ;  

现在可以通过使用obj_ptr指针使用堆中的NoHashObject对象成员了

  1. ... ...   
  2. delete rp ;释放资源   
  3. temp = (char)obj_ptr ;   
  4. obj_ptr = NULL ;防止悬挂指针产生   
  5. delete [] temp ;释放NoHashObject对象所占的堆空间。   

 

上面的实现是麻烦的,而且这种实现方式几乎不会在实践中使用,但是我还是写出来路,因为理解它,对于我们理解C++内存对象是有好处的。对于上面的这么多强制类型转换,其最根本的是什么了?我们可以这样理解:

某块内存中的数据是不变的,而类型就是我们戴上的眼镜,当我们戴上一种眼镜后,我们就会用对应的类型来解释内存中的数据,这样不同的解释就得到了不同的信息。

所谓强制类型转换实际上就是换上另一副眼镜后再来看同样的那块内存数据。

另外要提醒的是,不同的编译器对对象的成员数据的布局安排可能是不一样的,比如,大多数编译器将NoHashObject的ptr指针成员安排在对象空间的头4个字节,这样才会保证下面这条语句的转换动作像我们预期的那样执行:

  1. Resource rp = (Resource)obj_ptr ;  

但是,并不一定所有的编译器都是如此。既然我们可以禁止产生某种类型的C++堆对象,那么可以设计一个类,使之不能产生栈对象吗?当然可以。

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...