欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > C++内存管理

C++内存管理

2024/10/24 12:29:48 来源:https://blog.csdn.net/zc331/article/details/141401223  浏览:    关键词:C++内存管理

 一、前言

上图中介绍了C/C++中内存区域的基本划分,这里简单介绍:

  1. 栈:又叫堆栈,非静态局部变量、函数参数、返回值等都存放在栈里面;栈是向下生长的;
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可以使用动态接口创建动态的共享内存,做进程间通信;
  3. 堆用于程序运行时动态内存分配,堆是向上生长的;
  4. 数据段:存储全局数据和静态数据;
  5. 代码段:用于存储可执行代码和只读常量。

二、C++中申请内存和释放内存的方式

在C语言中,申请内存的方式是malloc/calloc/realloc,释放空间的方式是free。

在C++里面兼容了C里面的动态内存管理方式,但是用起来在有些地方不方便,所以C++提出了自己的动态内存管理方式:new和delete进行动态内存管理。

1、操作内置类型:

#include<iostream>
using namespace std;int main()
{//动态申请一个int类型的空间int* p1 = new int;//没有初始化,是随机值//动态申请一个int类型的空间并且进行初始化int* p2 = new int(1);//动态申请一个含10个int类型的数组int* p3 = new int[10];//没有进行初始化,是随机值//动态申请一个含10个int类型的数组并且进行部分初始化int* p4 = new int[10] {1, 2, 3};//前三个进行了初始化,后面默认是0delete p1;delete p2;delete[] p3;delete[] p4;return 0;
}

 注意:申请和释放单个空间使用new和delete,申请和释放连续的空间,使用new[]和delete[];要匹配起来使用。

2、操作自定义类型:

class A
{
public:A(int a=1):_a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}void Print(){cout << _a << endl;}
private:int _a = 1;
};int main()
{//动态申请一个A类型的空间A* p1 = new A;p1->Print();//动态开辟一个A类型的空间并且传参初始化A* p2 = new A(10);p2->Print();//释放空间delete p1;delete p2;return 0;
}

对于内置类型,使用new(delete)或者malloc(free)都是一样的;对于自定义类型,new和malloc的最大区别就是,new申请空间之后会调用构造函数,delete会调用析构函数之后再释放空间,而malloc和free不会

申请连续的自定义类型的空间:

class A
{
public:A(int a=1,int b=2):_a(a),_b(b){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}void Print(){cout << _a << endl;cout << _b << endl;}
private:int _a = 1;int _b = 2;
};int main()
{A aa1(1,1);A aa2(2,2);A aa3(3,3);//把连续申请的前三个自定义类型的拷贝构造初始化//方式一、利用已存在的对象拷贝构造A* p1 = new A[5]{ aa1,aa2,aa3 };delete[] p1;//方式二、匿名对象去拷贝构造A* p2 = new A[5]{ A(1,1),A(2,2),A(3,3) };delete[] p2;//方式三、隐式类型转化(注意传参的匹配)A* p3 = new A[5]{ {1,1},{2,2},{3,3} };delete[] p3;return 0;
}

 3、operator new和operator delete:

operator new和operator delete是两个全局函数,分别对应new和delete的一部分,它们分别在底层调用malloc和free函数,进行简单的动态申请空间或者释放空间;

operator new实际通过调用malloc函数来进行空间的申请,申请成功,那么就返回成功申请的空间的地址;若是失败,看用户有没有提供空间不足的应对措施,若是提供了,就继续申请,若是没有就抛异常。operator delete通过调用free函数来释放空间;

4、new和delete的实现原理:

若是申请的是内置类型,那么new和malloc就几乎没有什么区别;new和delete申请的单个空间,new[]和delete[]申请的是连续的空间;new申请失败抛异常,malloc申请失败返回NULL;

对于自定义类型:new首先调用opreator new进行空间的申请,再调用构造函数进行初始化;delete首先调用析构函数进行资源的清理,再调用operator delete进行空间的释放,

5、定位new表达式

定位new表达式就是对已经申请的原始空间调用构造函数进行初始化;

使用格式:

new(place_address)或者new(place_address)type(initializer-list)

place_address必须是一个指针,initializer-list是类型的初始化列表

使用场景:定位new表达式一般是配合内存池一起使用,内存池中的内存一般没用进行初始化,如果是自定义类型,就要使用定位new表达式显示调用构造函数对空间进行初始化 ;

class A
{
public:A(int a = 1) :_a(a){cout << "A() :" << this << endl;}~A(){cout << "~A() :" << this << endl;}void Print(){cout << _a << endl;}
private:int _a = 1;
};int main()
{//和malloc一样,但是没有初始化A* p1 = (A*)operator new(sizeof(A));A* p2 = (A*)operator new(sizeof(A));//定位new表达式显示调用构造函数new(p1)A;p1->Print();new(p2)A(10);p2->Print();//先调用析构函数p1->~A();p2->~A();//和free一样operator delete(p1);operator delete(p2);return 0;
}

只写operator new不会进行初始化; 

定位new表达式显示调用构造函数:

 对于显示调用构造初始化只能使用定位new表达式,不能利用指针的解引用;但是对于显示调用析构函数,要利用指针进行解引用。


三、new/delete和malloc/free之间的区别

  1. new无需进行类型的强转,它返回的申请空间就是那个申请的类型;但是malloc返回的空间的类型是void*的,要进行强转
  2. new对于自定义类型的可以进行初始化,但是malloc不行
  3. new/delete是操作符,malloc/free是函数
  4. malloc申请失败返沪NULL,因此要进行判断;但是new不用,但是要进行捕获异常;
  5. malloc/free申请和释放空间不会进行初始化或者析构;但是new/delete在申请空间之后会进行调用构造函数的操作,delete会先调用析构函数再进行空间的释放

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com