C++对象内存布局测试总结

SAP ERP销售应收&成本科目确定 ERP作为业财一体软件,其中最核心的就是业务与财务模块的自动集成,无需财务进行手工做账,提高工作效率的同时降低人工操作产生的误差。今天浅浅的分享一下SD模块生成会计凭证时,借贷项确定的系统配置。一般项目上借贷项、科目都有FICO提供,但是具体的集成配置是在SD这边。 阅读详情
                                                                                C++对象内存布局测试总结

 

   上文是半年前对虚函数、虚拟继承的理解。可能有一些错漏。而且只是理解了比较简单的部分,表达也不够清晰,这次决定花的时间再做一次总结。

  对于普通的C++对象内存布局,简单得不得了,就不做总结了。这里只总结涉及到虚拟继承的情况。

    因为不同编译器对虚拟继承的实现采用不同的方式,所以要完整的分析是不可能的。这里只考虑VS2005/2008,还有简单涉及GCC编译器。

1、 单个虚拟继承

只是为了分析而已,实际中并没有太大的作用。跟虚拟继承相关的派生类对象的内存布局跟具体的编译器相关。

   (1)VS编译器:无论有无虚函数,必然含有虚基类表指针。虚基类表中的内容为本类实例的偏移和基类实例的相对偏移值。如果有虚函数,那么基类的虚函数表跟派生类的虚函数表是分开的。

在内存布局上,地址从低到高,顺序如下:派生类的虚函数表指针+虚基类表指针+派生类的成员变量+“间隔”(4个字节)+基类的虚函数表指针+基类的成员变量。派生类跟基类实例的位置关系跟普通继承正好相反。

    说明:“间隔”产生的原因是派生类重写了基类的虚函数。如果没重写,则这一项没有。

    

图 1 VS编译器—单个虚拟继承

   (2)GNU的GCC编译器:跟VS的编译器类似,有不同的地方是,虚基类表跟派生类的虚函数表合并。另外通过虚基类表指针往正负两个方向寻址,可以获得不同偏移值,也就是说有两个功能一样的虚函数表。不过在实际应用的时候,不知道虚基类表是否真的有用,测试了简单的情况发现编译器做了优化,根本就没有用虚基类表来寻址虚基类实例。

 

图 2 GCC编译器—单个虚拟继承

2、 虚拟继承多个基类

虚基类表要增加内容,有N个虚基类就有N项基类实例偏移值,再加上1项本类实例的偏移值,也就是N+1。

假设C虚拟继承了A类和B类,考虑最复杂的情况(都有虚函数),那么C类对象的内存布局如下

 

(VS编译器):

C类虚函数表指针+虚基类表指针+C类成员变量+A类间隔(4个字节) + A类虚函数表指针+ A类成员变量+ B类间隔(4个字节)+B类虚函数表指针+ B类成员变量。

说明:当派生类重写了该基类的虚函数,才会有“间隔”。“间隔”属于虚函数被重新实现了的虚基类,可能是一个标志,也有可能是在函数调用的时候用上。不是很清楚。

 

图 3 VS编译器—虚拟继承多个基类

(GCC编译器):

C类虚函数表指针(包含虚基类表) + C类成员变量 + A类虚函数表指针 +  A类成员变量 + B类虚函数表指针 + B类成员变量。

相比较执行,使用GCC编译器,派生类对象小一些。(图略)

3、 虚拟继承之菱形继承

这里的菱形继承指的是:B、C虚拟继承A,然后D普通继承B、C。

D类的对象的内存布局如下

(VS编译器)

B类虚函数表指针(该虚函数表包含D类独有的虚函数的地址)+B类虚基类表指针+B类成员变量+C类虚函数表指针+C类虚基类表指针+C类成员变量+D类成员变量+“间隔”+A类虚函数表指针+A类成员变量。

说明:如果A类的虚函数没有被重写,那么就没有“间隔”。

 

图 4 VS编译器—菱形继承

(GCC编译器)

把B、C类的虚函数表跟虚基类表合并就是了。(图略)

4、VS编译器,“间隔”的疑问

 “间隔”的问题,在没有虚函数的情况下,重写是没有“间隔”的,所以觉得可能跟虚函数有关,也就是说是为了实现多态,具体是用在哪个地方,做了简单的反汇编调试(父类指针指向子类对象,调用被子类重写了的虚函数),并没有发现哪里用到了“间隔”,可能要在复杂的调用才会用上吧,目前搞不清楚。

5、虚基类表的问题

通过反汇编调试发现在使用多态的时候,VS编译器会去使用虚基类表,用于寻址虚基类地址。而GCC编译器则没有这么做,测试了比较简单的情况,发现它做了优化,并没有利用虚基类表,而是直接在派生类对象地址上加上一个常数,获得虚基类实例的地址。

 

 

学习参考:

http://blog.csdn.net/haoel/archive/2008/10/15/3081328.aspx

http://blog.csdn.net/BlueDog/archive/2009/10/22/4711169.aspx

《深度探索C++对象模型》应该是比较好的资料,但我是想通过编译器来理解它们的内存布局,所以上边的资料更好一些。

学习笔记( 11 ) - 解决:finalshell连接虚拟机(ubuntu)超时,主机ping不通虚拟机,主机没有VMnet8网卡, Connection refused: connect 解决:finalshell连接虚拟机(ubuntu)超时,主机ping不通虚拟机,主机没有VMnet8网卡, Connection refused: connect 阅读详情

相关推荐

Android 14.0 开机广播接收慢广播延迟问题分析

在14.0的系统rom定制化开发中,在某些时候在接收开机广播的时候发现,过了一分钟才收到开机广播,接下来就需要分析下 开机广播的相关分发机制,来处理下相关问题

安卓兼职framework和app工程师的博客 605

逆向分析之数据结构内存布局

数据结构分析 1.Vector vector<int> vec; vec.push_back(1); vec.push_back(2); vec.push_back(3); 初始化10h字节空间 第一个字段指向一个区域,区域中有一个指针,指向自己(this指针) 第二个字段存放数据起始地址 第三个字段存放数据末尾的下一个地址 第四个字段存放缓冲区末尾地址 2.list ...

w_g3366的博客 817

AE 与 ISP 参数联动机制解析:自动曝光系统与图像信号处理模块协同设计实践

AE(自动曝光)并不是一个独立的图像控制模块,而是与 ISP(Image Signal Processor)深度耦合运作的系统协同体。其输出的曝光参数直接决定了图像处理链路中 Gamma 曲线选择、黑电平补偿、去噪级别、边缘增强等一系列关键参数的取值。本文基于主流平台(如高通、MTK、海思)的工程实战经验,详细剖析 AE 与 ISP 在曝光驱动、调节优先级、图像还原逻辑等环节的联动机制,并结合拍照与视频等不同场景,给出可落地的联调方法。

努力分享一些人工智能、计算机视觉、影像等相关的知识干货! 1482

C++基础之std::map

Cartographer中要用到这里,之前都是直接用,了解不深,现在补,这里是纯搬的,手写一遍加深印象,源地址如下: 参考 std::map 容器使用详细说明_学之之博未若知之之要知之之要未若行之之实的博客-CSDN博客_std::map使用 概述: Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织.

YGG12022的博客 3万+

C++类几种情况的内存布局

关于C++内存布局的几种情况,需要多熟悉

蜗牛想飞翔 3864

C++性能优化(八)——内存分配机制

一、操作系统内存布局 1、32位系统经典内存布局 LinuxKernel 2.6.7前版本采用的默认内存布局形式如下: (1)32操作系统中,loader将可执行文件的各个段次依次载入到从0x80048000(128M)位置开始的空间中。应用程序能够访问的最后地址是0xbfffffff(3G)的位置,3G以上的位置是给内核使用的,应用程序不能直接访问。 (2)内存布局从低地址到高地址依次为:txet段、data段、bss段、heap、mmap映射区、stack栈区。 (3)heap和mm.

天山老妖 2842

C++对象内存布局测试总结【Z】

对于普通的C++对象内存布局,简单得不得了,就不做总结了。这里只总结涉及到虚拟继承的情况。     因为不同编译器对虚拟继承的实现采用不同的方式,所以要完整的分析是不可能的。这里只考虑VS2005/2008,还有简单涉及GCC编译器。 1、 单个虚拟继承 只是为了分析而已,实际中并没有太大的作用。跟虚拟继承相关的派生类对象内存布局跟具体的编译器相关。    (1)VS编译器:...

liuchang0001的专栏 192

C++对象内存布局--①测试虚函数表属于类

C++对象内存布局--①测试虚函数表属于类 测试1:同一个类的多个对象共享同一张虚函数表。 //虚函数表.cpp //2010年8月18日 //测试虚函数表,说明虚函数表属于类所有。同一个类的多个对象共享同一张虚函数表 //VS编译器 #include <iostream> using namespace std; class Base...

weixin_30699443的博客 76

C++对象内存布局--②测试派生类跟基类的虚函数表

C++对象内存布局--②测试派生类跟基类的虚函数表 测试2:父类虚函数表跟子类虚函数表是不同的。 //派生类跟基类的虚函数表.cpp//2010年8月18日//测试说明,父类虚函数表跟子类虚函数表是不同的。理解C++对象内存布局//VS编译器#include <iostream>using namespace std;///////////////////////...

weixin_30482181的博客 90

map内存结构

GNU实现的std::map的数据结构模型是红黑树。红黑树是平衡二叉树的一类变种。可以保证在最坏情况下花费O(logN)时间。 其着色性质有如下特性: 1,根节点是黑色的 2,每个节点要么是红色,要么是黑色 3,如果一个节点是红色,其子节点必须是黑色。 4,从一个节点到一个NULL指针的每一条路径必须包含相同数目的黑色节点 由上面的几条特性可以推论出,查找是一个

qk_xh的博客 2578

c++map内存布局

最后end()指向的是_M_header,其数据部分正好从_M_node_count的位置开始,it->first正好是_M_node_count的位置,it->second则是p的低4字节。有一个指针偶尔会置成0xffffffff,大佬查了几天发现是由于对map的end迭代器进行了错误操作导致的。_Rb_tree_key_compare里有一个_Compare类型的成员变量,std::less没有成员变量,如果使用默认的内存分配器,_Node_allocator里没有成员变量,不占空间。

https://gitee.com/liuyuan185442111/chest-view 1596

stl容器区别(内存布局和使用场合): vector list deque set map

set 和map都是无序的保存元素,只能通过它提供的接口对里面的元素进行访问。  set:集合, 用来判断某一个元素是不是在一个组里面,使用的比较少  map:映射,相当于字典,把一个值映射成另一个值(key,value),如果想创建字典的话使用它好了。 底层采用的是树型结构,多数使用平衡二叉树(要求对于每一个节点来说,它的左右子树的高度之差不能超过1)实现,查找某一值是常数时间,遍历起来效

Adrianna的专栏 3509

c++对象内存布局(虚函数)--上

对象的影响因素   简而言之,我们一个类可能会有如下的影响因素:   1)成员变量 2)虚函数(产生虚函数表) 3)单一继承(只继承于一个类) 4)多重继承(继承多个类) 5)重复继承(继承的多个父类中其父类有相同的超类) 6)虚拟继承(使用virtual方式继承,为了保证继承后父类的内存布局只会存在一份) 上述的东西通常是C++这门语言在语义方面对对象内部的影响因素,当然,还

stormbjm的专栏 654

浅谈C/C++内存泄漏及其检测工具

2006-04-03 09:00 作者: 出处: 温馨小屋 责任编辑:方舟 document.write("");document.write(""); 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题。已经有许多技术被研究出来以应对这个问

2874

RTTI

自从1993年Bjarne Stroustrup 〔注1 〕提出有关C++ 的RTTI功能之建议﹐以及C++ 的 例外处理(exception handling)需要RTTI﹔最近新推出的C++ 或多或少已提供RTTI。然而 ,若不小心使用RTTI﹐可能会导致软件弹性的降低。

C++ for Windows 之路 2万+

对字符串常量 的理解

常量存储总结 局部变量、静态局部变量、全局变量、全局静态变量、字符串常量以及动态申请的内存区1、局部变量存储在栈中2、全局变量、静态变量(全局和局部静态变量)存储在静态存储区3、new申请的内存是在堆中4、字符串常量也是存储在静态存储区补充说明:1、栈中的变量内存会随着定义所在区

C++ for Windows 之路 6781

High Efficiency Video Coding(HEVC_book)

High Efficiency Video Coding(HEVC_book)新一代视频压缩编码标准H.265权威书籍,介绍详尽,译文版,对于学习视频压缩编码标准和进行视频技术的人来说很重要的一本书。也是基础书籍。

CH340串口驱动-CH340 串口驱动最新版

CH340串口驱动是针对使用CH340和CH341系列USB转串口芯片的设备而设计的一款重要驱动程序。这些芯片广泛应用于各种电子设备中,如Arduino开发板、模块化电子模块、无线通信设备等,因为它们能方便地将设备连接到个人计算机的USB接口进行数据传输。驱动程序是操作系统与硬件设备之间的桥梁,确保系统能够识别并正确通信。我们要理解串口通信的基本概念。串行通信是一种数据传输方式,数据以比特流的形式按顺序逐位发送,通常用于连接距离较远的设备,因为它比并行通信更节省线路。在个人计算机上,传统的串口(COM口)逐渐被USB接口取代,而CH340和CH341芯片就是实现这种转换的关键组件。CH340和CH341芯片的主要功能包括:1. USB到串口的桥接:这两款芯片可以将USB信号转换为RS-232串行通信协议,使得不支持USB的设备可以通过USB接口与计算机通信。2. 支持多种波特率:它们能够适应各种波特率设置,如9600、115200等,以满足不同应用的需求。3. 兼容性广泛:由于支持32位和64位的Windows系统,包括最新的Windows 11,它们可以用于大多数现代计算机。驱动程序安装过程:1. 下载:用户需要找到与自己系统兼容的CH340串口驱动程序,例如"CH341SER"文件,通常是一个可执行的安装程序或ZIP压缩包。2. 解压:如果下载的是压缩文件,需先解压得到安装文件。3. 安装:运行安装程序,按照提示完成驱动的安装。通常会自动识别已连接的CH340或CH341设备,并安装相应的驱动。4. 验证:安装完成后,可以通过设备管理器检查是否成功安装。在“端口”类别下,应该能看到新增的虚拟串口,如COM3、COM4等。在实际应用中,CH340串口驱动还有以下几点需要注意:1. 如果设备在安装驱动后仍无法识别,可能需要检查USB线连接是否

上一篇: 每位开发人员都应铭记的10句编程谚语
下一篇: 虚函数的限制及多态性的有效范围
a199228
博客等级 码龄15年 92粉丝 57原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值