C/C++内存管理
1.C/C++中内存分布
- 栈又叫做栈堆,非静态局部变量/函数参数/返回值等等。栈是向下增长的
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库,用户可使用系统接口创建共享内存,做进程间通信
- 堆用于程序运行时动态内存分配,堆可以向上增长
- 数据段(静态区)存储全局数据和静态数据
- 代码段放可执行代码/只读常量
//text.cpp
#include<iostream>
using namespace std;
int globalvar = 1;
//全局变量放在静态区
static int staticvar = 1;
//全局静态变量也放在静态区
void Text()
{
static int staticvar = 1;
//局部静态也放在静态区
int localvar = 1;
//局部变量,放在栈里
int num[10] = { 1,2,3,4,5 };
//数组放在栈内
char char2[] = "abcd";
//将" a b c d \0" 拷贝给数组char2, 数组放在栈
*char2;
//数组名代表整个数值,对其解引用得到首元素,数值仍在栈内
const char* pchar3 = "abcd";
//const修饰,pchar3指向的内容不可修改,局部变量仍然在栈上开辟空间
*pchar3;
//数组名代表整个数值,对其解引用得到首元素,而"a b c d \0"是临时变量,所以存放在常量区
//变量的开辟在栈内
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4,sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
//动态开辟的内存在堆区,解引用得到首元素地址
*ptr1;
*ptr2;
*ptr3;
free(ptr1);
free(ptr3);
}
int main()
{
return 0;
}
2.C语言中动态内存管理方式:malloc/calloc/realloc/free
3.C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此·C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理
//text.cpp
#include<iostream>
using namespace std;
class A {
public:
A(int a=0,int b=0)
{}
~A()
{}
};
int main()
{
//动态申请一个int 类型的空间
int* p1 = new int;
//释放p1指向的空间
delete p1;
//动态申请10个int 类型的空间
int* p2 = new int[10];
//释放p2指向的空间
delete[] p2;
//动态申请+初始化
int* p3 = new int(5);
int* p4 = new int[10]{ 1,2,3,4,5 };
delete p3;
delete[] p4;
//动态申请一个A类并默认构造初始化
A* p5 = new A;
//动态申请一个A类并带参构造初始化
A* p6 = new A(1,0);
A* p7 = new A(1);
//动态申请一个A类数值并默认构造初始化
A* p8 = new A[3]{ {},{},{} };
//动态申请一个A类数值并带参构造初始化
A* p9 = new A[3]{ {1,2},{3,4},{5,6} };
A* p10 = new A[3]{ {1,2},{3,4},{} };
A* p11 = new A[3]{ {1,2} };
//先默认构造出三个对象,然后拷贝构造给动态开辟的数组
A aa1(1, 2);
A aa2(3, 4);
A aa3(5, 6);
A* p12 = new A[3]{ aa1,aa2,aa3 };
A* p13 = new A[3]{ A(1,2),A(3,4),A(5,6) };
return 0;
}
new和delete会调用构造和析构
class A {
public:
A(int a=0,int b=0)
{
cout << "A(int a=0,int b=0)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
int _a1 = 1;
int _a2 = 2;
};
int main()
{
A* ptr1 = new A;
delete ptr1;
return 0;
}
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间用new[]和delete[]。一定要匹配起来使用,否则容易内存泄漏,如下
class A {
public:
A(int a=0,int b=0)
{}
~A()
{}
int _a1 = 1;
int _a2 = 2;
};
class B {
private:
int _b1 = 1;
int _b2 = 2;
};
int main()
{//不报错
int* p1 = new int[10];// ->malloc
delete p1; //->free
B* p2 = new B[10];
delete p2;
//报错
A* p3 = new A[10];
delete p3;
return 0;
}
自定义类型在创建时会额外开一个整形放在开头记录对象个数,而编译器看到B没有写析构函数而优化了所以没有开,这个整形开辟是方便delete[]释放的,B释放的ptr2的指向的空间,释放完全,而A还有一个整型大小没有释放,所以内存泄漏报错
4.operator new 与 operator delete函数
- new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete 是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间
- operator new 实际也通过malloc来申请空间的,如果malloc
- 申请成功直接返回地址,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete最终是通过free来释放空间的
5.new 和 delete的实现原理
内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本相似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续的空间,而且new在申请空间失败时会抛异常,malloc会返回空
自定义类型
- new的原理
- 调用operator new函数申请空间
- 在申请空间上执行构造函数,完成对象的构造
- delete的原理
- 在空间上执行析构函数,完成对象中资源的清理工作
- 调用operator delete函数释放对象的空间
- new T[N]的原理
- 调用operator new[]函数,在operator new[]中实际调用operator new函数完成对N个对象空间的申请
- 在申请的空间上执行N次构造函数
- deleted[]的原理
- 在释放的对象空间上执行N此析构函数,完成对N个对象中资源的清理
- 调用operator delete[]释放空间,实际在operator delete[] 中调用operator delete来释放空间
原文地址:https://blog.csdn.net/2302_81171591/article/details/140552343
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!