c++学习笔记(14)-类的对象占用内存

news2025/2/4 13:01:29

1、类的对象占用内存大小

很多C++书籍中都介绍过,一个class对象需要占用多大的内存空间。最权威的结论是:
1. 非静态成员变量总和。
2. 加上编译器为了CPU计算,作出的数据对齐处理。
3. 加上为了支持虚函数,产生的额外负担。

1.1、空类的Size

class Car
{
};

void main()
{
    int size = 0;
    Car objCar;
    size = sizeof(objCar);
    printf("%s %d /r", "Class Car Size:", size);
}

输出结果:Class Car Size:1
这是为何呢?
编译器在执行Car objCar;这行代码后需要,作出一个Class Car的Object。并且这个Object的地址还是独一无二的,于是编译器就会给空类创建一个隐含的一个字节的空间。

1.2、只有成员变量的Size

class Car
{
private:
       int nLength;
       int nWidth;
};
void main()
{
       int size = 0;
       Car objCar;
       size = sizeof(objCar);
       printf("%s %d /r", "Class Car Size:", size);
}

输出结果:Class Car Size:8
这个结果很多开发人员都清楚。在32位系统中,整型变量占4个字节。这里Class Car中含有两个整型类型的成员变量,所以Class Size是8。

class Car
{
private:
       int nLength;
       int nWidth;
       static int sHigh;
};

void main()
{
       int size = 0;
       Car objCar;
       size = sizeof(objCar);
       printf("%s %d /r", "Class Car Size:", size);
}

输出结果:Class Car Size:8
我们这次在Class Car中添加了一个静态成员变量,但是Class Size仍然是8个字节。这正好符合了,结论中的第一条:非静态成员变量总合。

class Car
{
private:
       char chLogo
       int nLength;
       int nWidth;
       static int sHigh;
};

void main()
{
       int size = 0;
       Car objCar;
       size = sizeof(objCar);
       printf("%s %d /r", "Class Car Size:", size);
}

输出结果:Class Car Size:12
中又插入了一个字符型变量,结果Class Size变成了12。这个就是编译器额外添加3个字符变量,做数据对齐处理,为了是提高CPU的计算速度。编译器额外添加的东西我们是无法看见的。这也符合了结论中的第二条:加上编译器为了CPU计算,作出的数据对齐处理。

既然,我们这样定义类成员数据编译器会额外的增加空。那么,我们何不在定义类的时候就考虑到数据对齐的问题,可以多定义出3个字符类型变量作为预留变量,既能满足数据对齐的要求,也给自己的程序添加了一些可扩展的空间。

1.3、只有成员函数的Size

class Car
{
public:
       Car(){};
       ~Car(){};
public:
       void Fun(){};
};

void main()
{
       int size = 0;
       Car objCar;
       size = sizeof(objCar);
       printf("%s %d /r", "Class Car Size:", size);
}

输出结果:Class Car Size:1
噢,这是怎么回事儿呢?再做一个实验看看。

class Car
{
public:
       Car(){};
       ~Car(){};
public:
       void Fun(){};
private:
       int nLength;
       int nWidth;
};

void main()
{
       int size = 0;
       Car objCar;
       size = sizeof(objCar);
       printf("%s %d /r", "Class Car Size:", size);
}

输出结果:Class Car Size:8
这次应该很清楚的了。函数是不占用类空间的。第一个例子中的Size为1个字节,正是编译器为类创建一个隐含的一个字节的空间

class Car
{
public:
       Car(){};
       virtual ~Car(){};
public:
       void Fun(){};
};

void main()
{
       int size = 0;
       Car objCar;
       size = sizeof(objCar);
       printf("%s %d /r", "Class Car Size:", size);
}

输出结果:Class Car Size:4
这次,让析构函数为虚函数,看到了Class Size为4。这正是指向Virtual Table的指针vptr的Size。这正好符合了,结论中的第三条:加上为了支持虚函数,产生的额外负担。

到此为止,一个Class Object究竟占用多少内存空间,已经完全说清楚了。但是,这只是针对单独类,或者说是基类适用。对于子类,却不一样了。

1.4、类的对象成员函数不占用对象内存区

类的成员函数不占用对象内存区,函数的分布位置为.text段,同一个类实例化的所有对象共享相同的函数。

2、类的对象存储位置和对齐规则

通过几个测试场景来归纳一下类的成员变量存储的位置以及对齐规则
首先要知道每种类型的长度,以字节为单位:
image.png
结论先放这里:
1. 以最长字节类型(此处的类型也包括类)为准,所有元素都要与最长字节类型长度对齐(即,整个类的对象长度一定为最长字节类型长度的整数倍);
2. 所有类型的起始地址都可以整除该类型字节长度。
以下测试硬件架构:**x86_64(AMD64)

2.1、test case 1

#include <iostream>

using namespace std;

class Constr_Mem
{
public:
    Constr_Mem();
    char a;
    char b;
    char c;
    char d;
};

Constr_Mem::Constr_Mem()
{
}

int main()
{
    Constr_Mem constr_mem;
    cout << "size of the instance: " << sizeof(constr_mem) << endl;
    cout << "the address of a: " << (void*)&constr_mem.a << endl;
    cout << "the address of b: " << (void*)&constr_mem.b << endl;
    cout << "the address of c: " << (void*)&constr_mem.c << endl;
    cout << "the address of d: " << (void*)&constr_mem.d << endl;
    return 0;
}

输出:

size of the instance: 4
the address of a: 0x7ffddbd57d50
the address of b: 0x7ffddbd57d51
the address of c: 0x7ffddbd57d52
the address of d: 0x7ffddbd57d53

2.2、test case 2

修改class Constr_Mem如下:

class Constr_Mem
{
public:
    Constr_Mem();
    int a;
    char b;
    char c;
    char d;
};

输出:

size of the instance: 8
the address of a: 0x7ffcd4960200
the address of b: 0x7ffcd4960204
the address of c: 0x7ffcd4960205
the address of d: 0x7ffcd4960206

2.3、test case 3

修改class Constr_Mem如下:

class Constr_Mem
{
public:
    Constr_Mem();
    char a;
    int b;
    char c;
    char d;
};

输出:

size of the instance: 12
the address of a: 0x7ffdc7993150
the address of b: 0x7ffdc7993154
the address of c: 0x7ffdc7993158
the address of d: 0x7ffdc7993159

2.4、test case 4

修改class Constr_Mem如下:

class Constr_Mem
{
public:
    Constr_Mem();
    char a;
    short b;
    char c;
    char d;
};

输出:

size of the instance: 6
the address of a: 0x7fff2ad1ec70
the address of b: 0x7fff2ad1ec72
the address of c: 0x7fff2ad1ec74
the address of d: 0x7fff2ad1ec75

2.5、test case 5

修改class Constr_Mem如下:

class Constr_Mem
{
public:
    Constr_Mem();
    char a;
    short b;
    short c;
    int d;
};

输出:

size of the instance: 12
the address of a: 0x7fff0cb91d90
the address of b: 0x7fff0cb91d92
the address of c: 0x7fff0cb91d94
the address of d: 0x7fff0cb91d98

2.6、结论

1. 以最长字节类型(此处的类型也包括类)为准,所有元素都要与最长字节类型长度对齐(即,整个类的对象长度一定为最长字节类型长度的整数倍);
2. 所有类型的起始地址都可以整除该类型字节长度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1337362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【自然语言处理】扩展命名实体识别器(NER)以使用spaCy标记新实体

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

用C/C++实现MSML协议栈的详细介绍

一、MSML协议简介 MSML&#xff08;Media Server Markup Language&#xff09;是一种基于XML的标记语言&#xff0c;用于控制媒体服务器。它是媒体服务器控制协议的一种&#xff0c;允许第三方应用与媒体服务器进行交互&#xff0c;实现对媒体流的创建、修改和释放等操作。MSM…

Elasticsearch可视化平台Kibana [ES系列] - 第498篇

历史文章&#xff08;文章累计490&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 全…

W3 Total Cache Pro v2.6.0 – WordPress 插件

W3 Total Cache Pro v2.6.0&#xff1a;优化WordPress性能的专业解决方案 一、引言 在数字化的世界中&#xff0c;网站性能对于用户体验和搜索引擎排名至关重要。WordPress作为全球最受欢迎的内容管理系统之一&#xff0c;提供了大量的插件来帮助网站所有者优化其性能。其中&a…

数字人平台哪家好!

数字人是指利用人工智能技术&#xff0c;通过计算机生成或模拟人类的外貌、声音、动作和表情等特征&#xff0c;从而创造出具有一定个性和情感的虚拟角色。数字人可以用于于娱乐、教育、营销、服务等多个领域&#xff0c;为用户提供更加丰富和互动的体验。 目前&#xff0c;市场…

『JavaScript』深入理解JavaScript字符串的基础操作与内置方法

&#x1f4e3;读完这篇文章里你能收获到 学习了JavaScript中字符串的基本操作掌握了JavaScript字符串的多种内置方法了解了JavaScript中的模板字符串和插值表达式熟悉了如何在JavaScript中使用正则表达式与字符串方法结合 文章目录 一、基本操作1. 创建字符串2. 字符串长度3. …

Java架构师系统架构设计实践

目录 1 导语2 架构设计实践本章概述3 架构设计要素概述和规划4 架构设计模式5 架构设计输入6 架构设计输出7 架构设计要素总结 想学习架构师构建流程请跳转&#xff1a;Java架构师系统架构设计 1 导语 Java架构师在进行系统架构设计时&#xff0c;需要综合考虑多个方面&#…

洛谷 P2367 语文成绩 刷题笔记

P2367 语文成绩 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 差分 令a[i]为b[i]数组的前缀和 a[n]b[1]b[2]b[3].....b[n]; a[n-1]b[1]b[2]b[3].....b[n-1]; 构造差分数组 b[i]a[i]-a[i-1]; 有什么好处 当我们想对a[l]--a[r]范围内所有数据加上一个数x 不必循环 for(i…

C++力扣题目150--逆波兰表达式求值

给你一个字符串数组 tokens &#xff0c;表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意&#xff1a; 有效的算符为 、-、* 和 / 。每个操作数&#xff08;运算对象&#xff09;都可以是一个整数或者另一个表达式。两个…

前端---html 的基本结构

1. 结构代码 <!DOCTYPE html> <html><head> <meta charset"UTF-8"><title>网页标题</title></head><body>网页显示内容</body> </html>第一行<!DOCTYPE html>是文档声明, 用来指定页…

C# 使用xUnit进行单元测试

目录 写在前面 操作步骤 执行结果 写在前面 xUnit.net 是 NUnit 的作者Jim Newkirk搞的一个新的单元测试框架&#xff0c;目的是解决 NUnit 存在的一些问题和缺点&#xff0c;并在框架中加入一些最佳实践和扩展能力。 主要的改进点如下&#xff1a; 为每个测试方法产生一个…

漏洞复现-泛微OA xmlrpcServlet接口任意文件读取漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

什么是动态IP?静态IP和动态IP有什么区别?

动态IP(Dynamic IP)和静态IP(Static IP)它是指在计算机网络中分配给设备的两种不同类型的IP地址。 动态IP是指每次设备连接到网络时&#xff0c;网络服务提供商(ISP)IP地址的动态分配。当设备重新连接到网络时&#xff0c;它可能会被分配到不同的IP地址。动态IP适用于传统的家…

龙蜥开源操作系统能解决CentOS 停服造成的空缺吗?

龙蜥开源操作系统能解决CentOS 停服造成的空缺吗&#xff1f; 本文图片来源于龙蜥&#xff0c;仅做介绍时引用用途&#xff0c;版权归属龙蜥和相关设计人员。 一、《国产服务器操作系统发展报告&#xff08;2023&#xff09;》称操作系统已步入 2.0 时代&#xff0c;服务器操作…

【Leetcode 25】K 个一组翻转链表 —— 递归

25. K 个一组翻转链表 给你链表的头节点head&#xff0c;每k个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是k的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改…

2024深入评测CleanMyMac X4.14.6破解版新的功能

随着时间的推移&#xff0c;我们的Mac电脑往往会变得越来越慢&#xff0c;存储空间变得越来越紧张&#xff0c;这时候一个优秀的清理工具就显得尤为重要。作为一款备受好评的Mac清理工具&#xff0c;它能够为你的Mac带来全方位的清理和优化。在本文中&#xff0c;我们将深入评测…

Mac 右键拷贝文件失效

问题&#xff1a;Mac 右键拷贝文件失效&#xff0c;有时候拷贝可以成功&#xff0c;有时候拷贝不成功 发现问题所在&#xff1a;开了百度翻译的划词&#xff0c; 解决&#xff1a;把划词关掉就好了&#xff0c;或者设置划词快捷键翻译就好了&#xff0c;反正就不要一划就翻译那…

7.2 uvm_resource_db in UVM

uvm_resource_db是一个类型参数化 type-parameterized的类&#xff0c;它是资源数据库顶部的一个方便层(convenience layer)。这个便利层简化了对低级数据库的访问&#xff0c;并且没有添加新功能。因此&#xff0c;uvm_resource_db不是从uvm_resource类派生的。以下uvm_resour…

点坐标标签的可视化

说明 txt标签中按x&#xff0c;y格式存放点标签&#xff0c;如&#xff1a; 需要将这些点可视化在对应的图片上。 实现 import matplotlib.pyplot as plt# 读取包含点坐标的 txt 文件 file_path E:\projects\json\CDY_2015-berries.txt with open(file_path, r) as file:da…

Tg5032smn:高稳定性105℃高温

TG5032SMN是一款频率范围10MHz ~ 54MHz,具有高稳定的TCXO晶振&#xff0c;可与CMOS或限幅正弦输出。外部尺寸5.0 3.2 1.45mm&#xff0c;超小型,质地轻。该系列晶振的额定工作范围-40℃~&#xfe62;105C内可高稳定性工作&#xff0c;使得信号频率的误差很小。TG5032SMN与其他…