C++内存管理

一、C/C++ 内存分布

//全局数据和静态数据都存储在内存区域中的数据段
int golbalVar = 1;
static int staticGolbalVar = 1;
void Test()
{
	static int staticVar = 1;
	//非静态局部变量都位于栈中,栈是向下增长的
	int localVar = 1;
	int num[10] = { 1,2,3,4 };
	//以下两个为字符串常量,是只可读不可写的,因此位于内存区域中的代码段(可执行代码/只读常量存储)
	char ch[] = "abcd";
	const char* pchar3 = "abcd";
	//堆用于程序运行时的动态内存分配,堆是可以向上增长的
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4, sizeof(int));
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
	free(ptr1);
	free(ptr3);
}

总结内存区域存储:
栈(向下增长):非静态局部变量、函数参数、返回值等
堆(向上增长):动态内存分配
数据段:静态变量、全局变量
代码段:可执行代码、只读常量
malloc/realloc/calloc的区别:
malloc:动态申请一段连续的内存空间
realloc:在已经动态申请好的内存空间后面追加一段内存,但是如果此内存空间后面的连续空间不足我们想要申请的,我们就会重新找寻一段足够的空间,并将原来的内存空间中的内容copy过来。
calloc:动态申请内存并且可以进行默认的初始化,初始化为全0,但是我们在日常使用中很少需要初始化为全0,因此我们需要注意使用条件。

注意:动态申请内存空间固然方便,但是我们在使用完这段内存之后我们需要使用free函数手动释放空间,如果不释放空间,必然会造成内存泄漏,内存对于程序员而言还是十分重要的,因此我们要注意避免内存泄漏。

二、c++内存管理方式
c语言中的动态申请方式在C++中依然可以使用,但是有些地方处理起来不够方便我们使用,因此C++中采用new和delete来申请和释放空间。

void main()
{
	int* p1 = (int*)malloc(sizeof(int));
	//int* p1=(int*)calloc(1,sizeof(int));calloc申请空间后可以初始化为0
	if (p1 != NULL)
		return;//c语言申请内存空间
	*p1 = 10;
	int* p2 = new int(100);//new可以在申请空间后直接进行初始化
	free(p1);
	delete p2;//释放内存空间
	int* p3 = (int*)malloc(sizeof(int) * 10);
	free(p3);
	int* p4 = new int[10]{ 0,1,2,3,4,5,6,7,8,9 };//申请数组的初始化(c++11支持)
	delete []p4;//释放数组空间
}
void Test
{
//动态申请一个int类型的空间
	int* ptr4=new int;
//动态申请一个int类型的空间并初始化为10
	int* ptr5=new int(10);
//动态申请十个int类型的空间
	int* ptr6=new int[10];
	delete ptr4;
	delete ptr5;
	delete []ptr6;
}

注意:使用new和delete操作符申请释放连续的内存空间,使用new[]和delete[]

new和delete操作自定义类型

class Test
{
public:
	Test(int data=0):m_data(data)
	{
		cout << "Test():" << this << endl;
	}
	~Test()
	{
		cout << "~Test():" << this << endl;
	}
private:
	int m_data;
};
//C语言方式申请
void Test2()
{
	//动态申请单个Test类型的空间
	Test* p1 = (Test*)malloc(sizeof(Test));
	free(p1);
	//动态申请10个Test类型的空间
	Test* p2 = (Test*)malloc(sizeof(Test));
	free(p2);
}
//C++方式申请
void Test3()
{
	Test* p1 = new Test;
	delete p1;
	Test* p2 = new Test[10];
	delete[]p2;
}

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc和free不会。

在这里,我们要区分三个概念:
1、new operator 和delete operator
2、operator new 和operator delete 函数
3、placement-new(定位new)
我们的new operator 和 delete operator 函数就是new和delete操作符,使用new和delete 就是先调用全局函数operator new和operator delete函数进行动态申请内存空间,operator new和operator delete函数在底层也是通过malloc和free进行操作的,因此我们可以清楚的了解到new和delete分两步走,第一步进行空间申请(并且new申请空间失败会抛出异常),第二部在已申请好的空间上调用构造函数。定位new表达式是在已分配的原始内存空间调用构造函数初始化一个对象。

定位new表达式

class Test
{
public:
	Test(int data=0):m_data(data)
	{
		cout << "Test():" << this << endl;
	}
	~Test()
	{
		cout << "~Test():" << this << endl;
	}
private:
	int m_data;
};
void main()
{
	//申请空间
	Test* pt = (Test*)malloc(sizeof(Test));
	//调用构造函数初始化对象
	new(pt)Test;
}

使用形式:
1.new(place_address) type
2.new(place_address)type(initializer-list)
place-address 必须是一个指针,initializer-list是类型的初始化列表

malloc/free和new/deete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:

  1. malloc和free是函数,new和deete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,因为new后跟的是空间类型
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

内存泄漏:

void MemoryLeaks()
{
	//1.申请了内存忘记释放
	int *p1=(int*)malloc(sizeof(int));
	int *p2=new int;
	//2.异常安全问题
	int *p3=new int[10];
	Func();//这里的func函数抛出异常导致delete[]p3未执行
	delete []p3;
}

内存泄漏我们一定要严加预防,这也是一个好的程序员的基本素养
解决方案:
1、事前预防
2.事后查错

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值