一,C/C++内存模型
1.内存模型分类
- 栈区:由编译器自动分配和释放,用来存放函数的参数,局部变量。存放在栈中的数据只在当前函数及下一层函数中有效,函数一旦结束,这些数据就被释放了。
- 堆区:由程序员分配和释放,如果程序员没有释放则在程序结束时由OS释放,由于忘记释放通常会出现内存泄露问题。
- 全局(静态)区:用来存储全局变量和静态变量,程序结束时由OS释放。
- 常量区:存放字面量,不允许修改,如字符串"Hello,Unreal",程序结束时由OS释放。
- 代码区:存放代码(如函数),不允许修改(类似常量区),但可以执行(不同于常量区)。
2.理解函数,代码和内存分配的问题
函数是由一条条的操作指令(代码)组合而成的,其指令可以是定义变量向内存申请空间,或者是操作指令,例如两数相加。
二,C++中类和对象的内存分配模型
1.C++中类和对象
在C语言中,“数据”和“函数”是分开来声明的,也就是说,语言并没有支持“语言和函数”之间的关联性。但是在C++中却提供了“类”来将“数据”和“函数”绑定在了一起。C++中的类由成员变量,静态成员变量,构造函数,成员函数,静态函数和虚函数组成。下面我们来研究组成类的数据和函数是如何在内存中分配的。
2.C++中是如何管理类和对象的
我们首先来定义几个类,然后对下面的代码进行分析。
# include<iostream> using namespace std; /* 定义第一个类:12个字节 */ class C1 { private: int a;// 4 int b;// 4 int c;// 4 }; /* 定义第二个类:12个字节 */ class C2 { private: int a;// 4 int b;// 4 int c;// 4 static int d;// 0 }; /* 定义第三个类:4个字节 */ class C3 { private: int a;// 4 static int b;// 0 public: void setA(int a)// 0 { this->a = a; } int getA()// 0 { return this->a; } static void add()// 0 { C3::b += 100; } }; /* 定义结构体:4个字节 */ struct S1 { int a; static int b; }; int main() { cout << "C1类所占字节数:" << sizeof(C1) << endl; cout << "C2类所占字节数:" << sizeof(C2) << endl; cout << "C3类所占字节数:" << sizeof(C3) << endl; cout << "S1结构体所占字节数:" << sizeof(S1) << endl; return 0; }
3.上述代码结果分析
- C++中的成员变量和成员函数是分开存储的。
- 普通的成员变量存放在对象(变量)中,与结构体变量有相同的内存布局和字节对齐方式。
- 静态成员变量存储在全局(静态)区。
- 成员函数和静态函数存储在代码区。
4.C++成员变量存放在对象中,那么成员函数是如何管理的?
5.上述代码总结
- C++的类是用结构体实现的,因此类中的成员变量和结构体里的变量内存布局方式一致。
- C++类中的成员函数隐式包含一个指向当前对象的指针,哪个对象调用该函数,C++编译器就默认将该对象包含在函数中。
- 静态成员变量和静态成员函数属于类,因此静态成员函数不包含指向具体对象的指针。
6.this指针
- 通过上述示例,我们发现类中的普通成员函数包含一个this指针,该指针指向调用当前函数的对象,即谁调用我,我就指向谁。
- this指针通常用于在成员函数或者构造函数的形参和成员变量一致的时候,用this指针来表示当前对象的成员变量,形参直接赋值给成员变量即可。