(一)内存分区
1. 代码区
- 存放函数体的二进制代码,由操作系统进行管理。
- 在程序运行前,程序编译后 就存在。
- 特点:共享、只读。
2. 全局区
- 存放全局变量、静态变量、常量(字符串常量、const修饰的全局常量)。
- 在程序运行前 就存在。
3. 栈区
- 由编译器自动分配和释放,存放函数的参数值、局部变量等。
- 在程序运行后 存在。
- 不要返回局部变量的地址,栈区开辟的数据由编译器自动释放!
int* fun(){ // 形参也会放在栈区
int a = 10; // 局部变量,存放在栈区,栈区的数据在函数执行完后,自动释放return &a; // 返回局部变量的地址
}
int main(){
int *p = func();cout << *p << endl; // 第一次输出为10,是因为a原来的内存还没有被覆盖,还可以输出
cout << *p <<endl; // 输出的时候,已经被别的数据覆盖了,所以输出的内容是不可控的
system("pause");
}
4. 堆区
- 由程序员分配和释放,若程序员不释放,程序结束时操作系统回收。
(二)内存管理(C++相关的一些编码规范)
1、能不使用动态内存的尽量不使用,例如:用vector来替换动态数组...
2、能不自己管理内存的尽量不自己管理,可以使用 智能指针、对象树 等技术管理裸指针;
3、使用 delete 和 new 来代替 free 和 malloc;
4、new与delete尽量匹配使用,注意 [] 的使用;
5、释放前检查是否为空,释放后及时置空;
#define SAFE_DELETE(aPointer) \
{ \
if (nullptr != aPointer) \
{ \
delete aPointer; \
aPointer = nullptr; \
} \
} \
6、在外部函数分配的堆内存,不要在调用函数内释放,应该在外部函数内释放;
7、尽量在构造函数里分配内存,在析构中回收;
8、基类及继承类各自管理自身内存;
9、若类中存在动态成员,须提供 拷贝构造函数、拷贝赋值函数、移动构造函数(可选)、移动赋值函数(可选),或禁用这些函数;
10、当类中存在虚函数时,将类的析构函数定义为虚函数;
11、使用智能指针管理数组时,虚提供删除器。