C++ 分配内存释放内存

C++ 分配内存释放内存


一、new、delete、malloc和free

最简单的分配内存

cpp 复制代码
	int* p_m = (int*)malloc(sizeof(int));
	int* p_n = new int;

自定义对象分配和释放内存

让我们定义如下的对象

cpp 复制代码
class TestClass
{
public:

	TestClass()
	{
		cout << "构造函数调用" << endl;
	}

	~TestClass()
	{
		cout << "析构函数调用" << endl;
	}

	int a = 0;
	int b = 0;
};

然后使用new和malloc分配内存,使用delete和free分别释放

cpp 复制代码
	TestClass* p_m1 = (TestClass*)malloc(sizeof(TestClass));
	TestClass* p_n1 = new TestClass();

	delete p_n1;
	free(p_m1);

我们会发现最终只有new 和 delete 配对的方式走了生命周期

那我们把他们换过来配对会怎么样呢

cpp 复制代码
	TestClass* p_n1 = new TestClass();
	free(p_n1);
cpp 复制代码
	TestClass* p_m1 = (TestClass*)malloc(sizeof(TestClass));
	delete p_m1;

可以看到:

delete 释放都会调用析构函数,而free都不会调用。

new 可以调用构造函数,而malloc不会调用构造

如果要使用生命周期的话使用new是较好的选择

二、new、delete与虚析构的问题

我们定义一个有着继承关系的结构

cpp 复制代码
class BaseClass
{
public:

	BaseClass()
	{
		cout << "Base构造函数调用" << endl;
	}

	~BaseClass()
	{
		cout << "Base~析构函数调用" << endl;
	}

	int a = 0;
	int b = 0;
};

class ChildClass : public BaseClass
{
public:
	ChildClass()
	{
		cout << "Child构造函数调用" << endl;
	}

	~ChildClass()
	{
		cout << "Child~析构函数调用" << endl;
	}
};

然后我们分配内存和释放内存,看看构造与析构是怎么样的

cpp 复制代码
	ChildClass* Child = new ChildClass();
	delete Child;

现在我们使用多态去定义

cpp 复制代码
	BaseClass* Child1 = new ChildClass();
	delete Child1;

我们发现这时候并没有调用子类的析构了,我们需要给父类析构变成虚析构

最终代码

cpp 复制代码
class BaseClass
{
public:

	BaseClass()
	{
		cout << "Base构造函数调用" << endl;
	}

	virtual ~BaseClass()
	{
		cout << "Base~析构函数调用" << endl;
	}

	int a = 0;
	int b = 0;
};

class ChildClass : public BaseClass
{
public:
	ChildClass()
	{
		cout << "Child构造函数调用" << endl;
	}

	~ChildClass()
	{
		cout << "Child~析构函数调用" << endl;
	}
};

int main()
{
	ChildClass* Child = new ChildClass();
	delete Child;

	cout << "=========================" << endl;

	BaseClass* Child1 = new ChildClass();
	delete Child1;

	system("pause");
	return 0;
}

三、一维、二维、多维数值创建和释放

一维

cpp 复制代码
	TestClass* Arr = new TestClass[10];
	delete[] Arr;

二维

cpp 复制代码
	// 创建
	TestClass** Arr = new TestClass*[3];
	for (size_t i = 0; i < 3; i++)
	{
		Arr[i] = new TestClass[3];
	}

	// 释放
	for (size_t i = 0; i < 3; i++)
	{
		delete[] Arr[i];
	}
	delete[] Arr;

多维

cpp 复制代码
	// 创建
	TestClass*** Arr = new TestClass**[2];
	for (size_t i = 0; i < 2; i++)
	{
		Arr[i] = new TestClass*[2];
		for (size_t j = 0; j < 2; j++)
		{
			Arr[i][j] = new TestClass[2];
		}
	}

	// 释放
	for (size_t i = 0; i < 2; i++)
	{
		for (size_t j = 0; j < 2; j++)
		{
			delete[] Arr[i][j];
		}
		delete[] Arr[i];
	}
	delete[] Arr;

四、new的缺点以及连续内存的优点

内存碎片产生原因:

1、小块内存分配​​:

频繁分配不同大小的对象

内存分配器需要不断寻找合适大小的内存块

cpp 复制代码
for (int i = 0; i < 10000; i++) {
    // 频繁分配不同大小的对象
    auto* obj1 = new SmallObject();   // 例如 16 字节
    auto* obj2 = new MediumObject();  // 例如 64 字节
    auto* obj3 = new LargeObject();   // 例如 256 字节
    
    // 释放部分对象
    delete obj2; // 在内存中留下中等大小的空隙
}

2、非连续释放​​:

对象以随机顺序创建和销毁

在已分配内存中留下大小不一的"空洞"

3、内存分配器限制​​:

无法合并相邻的小空闲块

新分配的对象无法放入这些"空洞"

频繁的new对象会有大量的内存碎片产生,可以预先分配一块内存进行取用

cpp 复制代码
template<typename T>
class FPreCacheData
{
public:
	FPreCacheData(int size)
	{
		Size = size;
		DataPtr = new T[size];
	}

	inline int GetSize() { return size; }

	T& operator[](int index) 
	{
		return DataPtr[index];
	}

private:
	int Size;
	T* DataPtr;
};
cpp 复制代码
	FPreCacheData<TestClass> PreCacheData = FPreCacheData<TestClass>(100);
	TestClass& a = PreCacheData[20];
相关推荐
汉克老师1 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++
晴天的雨.9922 小时前
【C++】继承篇
java·开发语言·c++
青少儿编程课堂2 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛
another heaven2 小时前
【C/C++ 第一次跨越(上):用 C++11/14 停止制造新的旧代码】
c语言·c++·制造
qq_406981032 小时前
c++ lamda(三)Lambda表达式
java·前端·c++
I_belong_to_jesus13 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Rabitebla14 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
码客-ygluu20 小时前
一个通用游戏数据服务器
c++·架构
another heaven20 小时前
【C/C++ Ranges 是零开销抽象吗?拆开管道、惰性求值和编译期膨胀】
c语言·开发语言·c++
YLCHUP1 天前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论