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];