C++中类的内存空间大小(sizeof)分析

首先明确各数据类型占多大的空间。例如int到底是占2字节还是4字节空间:

在TC里,int是2字节的(主要是因为TC是16位的,所以int类型也该是16位的)
VC++里,int是4字节的,因为现代操作系统下的软件大多是是32位。
64位的VC++,本来按理说,该是8字节的,但是可能为了维持32位的源代码移植到64位尽量不出错,所以也维持了4字节的长度。
至于其他有名的编译器,如gcc,我还没用过,你得查一查它所规定int的长度

或者利用sizeof(int)也可以计算出来。本人电脑上计算如下:

在C语言中存在关于结构体的存储空间大小是比较深入的话题,其中涉及计算机的基本原理、操作系统等。我认为对齐是C语言中让很多初学者都拿不准摸不透的问题,特别是在跨平台的情况下,对齐这种问题更加的复杂多变,每一种系统都有自己独特的对齐方式,在Windows中经常是以结构体重最大内置类型的存储单元的字节数作为对齐的基准,而在Linux中,所有的对齐都是以4个字节对齐。

那么在C++中的类的内存空间大小又有哪些特殊的问题呢?

首先,我认为对齐肯定也是其中的问题之一,对齐主要是为了加快读取的速度。

关于对齐这个我认为基本上已经是操作系统内定好的,既然Linux与Windows存在差别,那么在C++的类中,关于对齐肯定也会存在一定的差别。关于对齐我认为只要记住平时使用的系统的对齐准则就可以了,即:在Windows中经常是以结构体重最大内置类型的存储单元的字节数作为对齐的基准,而在Linux中,所有的对齐都是以4个字节对齐。

其次,我认为就应该讨论在基类中哪些成员占有存储空间,那些成员不占用内存空间?

在C++中占存储区间的主要是非static的数据对象,主要包括各种内置的数据类型,类对象等,类中的函数声明以及函数定义都不算内存空间。但是需要注意所有的virtual函数(虚函数)共享一段内存区域,一般来说是4个字节。为什么只是包含非static数据对象呢?因为static数据并不属于类的任何一个对象,它是类的属性,而不是具体某一个对象的属性,在整个内存区域中只有一个内存区域存储对应的static数据,也就是所有的类对象共享这个数据,所以不能算做具体某一个对象或者类型的内存空间。

因此可以认为基类对象的存储空间大小为:

    非static数据成员的大小 + 4 个字节(虚函数的存储空间)

当然这个大小不是所有数据成员大小的叠加,而是存在一个对齐问题,具体的应该参考相关的对齐文章。

最后,我认为肯定要关心一下派生类的存储空间了?

在C++中,继承类是一个比较有用的类,继承使得各种类在基类的基础上扩展,这时候派生类中包含了基类的信息,一般而言,在基类中存在虚函数时,派生类中继承了基类的虚函数,因此派生类中已经继承了派生类的虚函数。因此继承类中不能再添加虚函数的存储空间(因为所有的虚函数共享一块内存区域),而仅仅需要考虑派生类中心添加进来的非static数据成员的内存空间大小。

因此可以认为派生类对象的存储空间大小为:

    基类存储空间 + 派生类特有的非static数据成员的存储空间

   还有一类是比较特殊的情况,如果是虚继承的情况下,这时的存储空间大小就会发生变化。

    基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每一个类的虚函数存储空间。

下面我采用一些例子说明上面的问题:

#include <iostream>
using namespace std;
class test
{
public:
        test();
private:
        int a;
        char c;
};
int main()
{
    cout << sizeof(test) << endl;
    //system("pause");//按Ctrl+F5
    return 0;
}

上面的代码在linux以及windows下都会输出8,而不是输出5,这个是在C语言中已经讨论过的话题,但是说明对齐在C++中也是要考虑的。关于操作系统的差异在后面用一个统一的例子说明。

虚函数问题

为了讨论虚函数,我们在test类中添加一个虚析构函数,然后再测试结果。

class test
{
public:
        test();
        virtual ~test();
private:
        int a;
        char c;
};

这段代码与前面的代码没有什么区别,只是添加了一个虚函数,然后编译调试,这时候输出的结果12,也就是说增加了一个虚函数以后,类的数据成员增加了4个字节,那么是否是每一个虚函数都占有4个字节呢?其实是不会的,在test中加入一个新的虚函数virtual void get_a_c(),这时在输出的结果还是12,这说明所有的虚函数共享4个字节。

static数据

我们知道static数据是非对象的属性,而是类的属性,他不能算是某一个对象或者类型的存储空间,在类定义中只能声明,初始化只能在类外执行,当然有例外的。这也不做分析了。具体参看后面的大例子。

派生类的存储空间

派生类从基类中继承了很多成员,自己也会增加很多的成员,由于虚函数也会被继承下来,所以就是在派生类中不显式定义虚函数,在派生类中也会存在从基类继承下来的虚函数,因此虚函数不需要额外计算内存空间,而只需要增加基类的非static成员数据大小。定义如下面所示,该函数会输出20,刚好是添加的非static数据double d的存储空间大小。证明了上面的分析。

#include <iostream>
using namespace std;
class test
{
public:
        test();
        virtual ~test();
        virtual void get_a_c();
private:
        int a;
        char c;
};
class derived_test:public test
{
public:
    virtual ~derived_test();
private:
    double d ;
};
int main()
{
    cout << sizeof(derived_test) << endl;
    return 0;
}

测试虚继承的类的大小:

#include <iostream>
using namespace std;
class A
{
    char i[3];
public:
    virtual void a(){};
};
class B : public virtual A
{
    char j[3];
public:
    virtual void b(){}
};
class C: public virtual B
{
    char k[3];
public:
    virtual void c(){}
};
int main()
{
    cout << "sizeof(A): " << sizeof(A) << endl;
    cout << "sizeof(B): " << sizeof(B) << endl;
    cout << "sizeof(C): " << sizeof(C) << endl;
    return 0;
}

输出结果为:

如果是虚继承的情况下,这时的存储空间大小就会发生变化。

    基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每一个类的虚函数存储空间。

另外,如果A类改成如下形式:

class A
{
    char i[5];
public:
    virtual void a(){};
};

所占空间:12。因为

class A
{
    char i[9];
public:
    virtual void a(){};
};

所占空间:16。因为

class A
{
    char i[3];
    char t;
public:
    virtual void a(){};
};

所占空间:8。因为

class A
{
    char i[3];
    char t;
    char t1;
public:
    virtual void a(){};
};

所占空间:12。因为

时间: 2024-10-27 07:26:31

C++中类的内存空间大小(sizeof)分析的相关文章

c++类占内存空间大小计算

x64环境下实现: 1 #include <iostream> 2 3 using namespace std; 4 5 class kong{ 6 7 }; 8 9 class kong1{ 10 11 }; 12 13 class kong2{ 14 15 }; 16 17 class data2 18 { 19 int a; //4个字节 20 char s; 21 }; 22 23 class data3 24 { 25 int a; 26 char s; 27 virtual voi

文件内存空间大小计算

/** *  要求计算一个文件中所有文件的大小 注意:必须先计算一个文件夹中所有文件的大小必须先拿到所有文件,然后再获取所有文件的大小,然后相加 */ NSFileManager *manager=[NSFileManager defaultManager]; //提取要求计算的文件 NSArray *arr=[manager subpathsAtPath:@"/Users/zhangyunjiang/Desktop"]; NSMutableString *strM=[NSMutabl

goto,void,extern,sizeof分析

goto: 程序的质量与goto出现的次数成反比,禁用 goto的副作用:破环了程序的结构化的顺序执行的过程,它有可能会跳过程序的应该执行的一些步骤. void: 修饰函数返回值和参数 c语言中没有定义void的内存空间的大小,无法在内存中裁剪出void对应的变量,但是不同的编译器,可能为该数据类型定义了内存空间大小,并且标准还不一致. printf("%d\n",sizeof(void));执行的结果在不同的编译器中,结果可能不同. void*: 作为左值,用于接收任意类型的指针 作

内存地址与内存空间

概览 基本概念 进入误区 误区诊断 总结 基本概念 什么是位? 什么是字节? 位表示的是二进制位,一般称为比特,即0或1,是计算机存储的最小单位: 字节是计算机中数据处理的基本单位: 计算机中以字节为单位存储和解 释信息,规定一个字节由八个二进制位构成,即1个字节等于8个比特. 1Byte=8bit 地址总线? (1)CPU是通过地址总线来指定存储单元的. (2)地址总线决定了cpu所能访问的最大内存空间的大小. (3)地址总线是地址线数量之和. 内存地址? 是一种用于软件及硬件等不同层级中的数

虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

#include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout << "A:A" <<endl; } virtual void getb(){ cout << "A:B" <<endl; } }; class B :public A{ public: B(){} virtual void g

PHP数组实际占用内存大小的分析

一般来说,PHP数组的内存利用率只有 1/10, 也就是说,一个在C语言里面100M 内存的数组,在PHP里面就要1G.下面我们可以粗略的估算PHP数组占用内存的大小,首先我们测试1000个元素的整数占用的内存: <?php echo memory_get_usage() , '<br>'; $start = memory_get_usage(); $a = Array(); for ($i=0; $i<1000; $i++) { $a[$i] = $i + $i; } $mid 

[转]sizeof计算空间大小的总结

原文链接:http://www.cnblogs.com/houjun/p/4907622.html 关于sizeof的总结 1.sizeof的使用形式:sizeof(var_name)或者sizeof var_name 2.变量名可以不用括号括住:sizeof a 3.数据类型必须用括号括起来:sizeof(int) 4.sizeof可以对表达式求值:sizeof(2+3.14),实际是sizeof(double) 5.sizeof可以对函数调用求值,实际上是对返回值类型求值 6.以下情况不能用

【转】内存分配粒度vs内存分页大小vs内存空间

原帖地址 分配粒度:表示每次请求内存的时候最小给分配多少,比如32位操作系统基本上每次分配的是64K大小. 分页大小:表示的是页面的大小,32位操作系统是4K是内存管理的最小单位. 例如: 假设你要请求6k = 4K + 2K的空间,操作系统会一次分配64K的空间放着,又因为内存最小操作单位是4K,所以实际上给你分配了8K=4K + 4K,剩下的56K放着有需要了再给你. WIN32 操作系统为每个进程分配4G的内存空间,程序的代码,常量变量都分配在这4G内存空间上. 这里提到的内存空间跟内存条

Android first---外置内存剩余空间大小

####获取外置内存的大小#### public class MainActivity extends Activity { @SuppressWarnings("deprecation")    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activi