C++ 分配內存釋放內存
- 一、new、delete、malloc和free
- 最簡單的分配內存
- 自定義對象分配和釋放內存
- 二、new、delete與虛析構的問題
- 三、一維、二維、多維數值創建和釋放
- 一維
- 二維
- 多維
- 四、new的缺點以及連續內存的優點
一、new、delete、malloc和free
最簡單的分配內存
int* p_m = (int*)malloc(sizeof(int));int* p_n = new int;
自定義對象分配和釋放內存
讓我們定義如下的對象
class TestClass
{
public:TestClass(){cout << "構造函數調用" << endl;}~TestClass(){cout << "析構函數調用" << endl;}int a = 0;int b = 0;
};
然后使用new和malloc分配內存,使用delete和free分別釋放
TestClass* p_m1 = (TestClass*)malloc(sizeof(TestClass));TestClass* p_n1 = new TestClass();delete p_n1;free(p_m1);
我們會發現最終只有new 和 delete 配對的方式走了生命周期
那我們把他們換過來配對會怎么樣呢
TestClass* p_n1 = new TestClass();free(p_n1);
TestClass* p_m1 = (TestClass*)malloc(sizeof(TestClass));delete p_m1;
可以看到:
delete 釋放都會調用析構函數,而free都不會調用。
new 可以調用構造函數,而malloc不會調用構造
如果要使用生命周期的話使用new是較好的選擇
二、new、delete與虛析構的問題
我們定義一個有著繼承關系的結構
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;}
};
然后我們分配內存和釋放內存,看看構造與析構是怎么樣的
ChildClass* Child = new ChildClass();delete Child;
現在我們使用多態去定義
BaseClass* Child1 = new ChildClass();delete Child1;
我們發現這時候并沒有調用子類的析構了,我們需要給父類析構變成虛析構
最終代碼
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;
}
三、一維、二維、多維數值創建和釋放
一維
TestClass* Arr = new TestClass[10];delete[] Arr;
二維
// 創建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;
多維
// 創建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、小塊內存分配??:
頻繁分配不同大小的對象
內存分配器需要不斷尋找合適大小的內存塊
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對象會有大量的內存碎片產生,可以預先分配一塊內存進行取用
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;
};
FPreCacheData<TestClass> PreCacheData = FPreCacheData<TestClass>(100);TestClass& a = PreCacheData[20];