欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++之動態(tài)內(nèi)存管理方式(new delete)

 更新時間:2025年09月17日 09:15:18   作者:MzKyle  
C++中new/delete集成內(nèi)存分配與對象構(gòu)造析構(gòu),是面向?qū)ο髢?nèi)存管理的核心,與malloc/free相比,支持類型安全、異常處理及數(shù)組操作,需嚴(yán)格配對使用,現(xiàn)代開發(fā)推薦智能指針替代,以提升安全性與自動化程度

在C/C++編程中,動態(tài)內(nèi)存管理是核心能力之一,而newdelete正是實現(xiàn)這一功能的關(guān)鍵操作符。

它們不僅是內(nèi)存分配與釋放的工具,更與對象的生命周期、資源管理深度綁定。

一、new與delete的設(shè)計初衷:超越“內(nèi)存分配”的對象管理

C語言通過malloc()free()實現(xiàn)動態(tài)內(nèi)存管理,但這兩個函數(shù)僅關(guān)注“內(nèi)存塊的分配與釋放”,與“對象”無關(guān)——它們不會處理對象的初始化(構(gòu)造)和清理(析構(gòu))。而C++作為面向?qū)ο笳Z言,需要一種能將“內(nèi)存分配”與“對象構(gòu)造”綁定、“內(nèi)存釋放”與“對象析構(gòu)”綁定的機制,newdelete由此誕生。

簡單來說:

  • new = 分配內(nèi)存 + 調(diào)用構(gòu)造函數(shù)(初始化對象);
  • delete = 調(diào)用析構(gòu)函數(shù)(清理對象資源) + 釋放內(nèi)存。

這種“內(nèi)存操作”與“對象生命周期”的綁定,是new/deletemalloc()/free()的核心區(qū)別,也是C++面向?qū)ο筇匦缘闹匾巍?/p>

二、new的工作原理與語法形式

new的核心功能是“在堆上創(chuàng)建對象”,其操作可分解為兩個步驟:

  1. 調(diào)用operator new函數(shù)分配原始內(nèi)存(大小為對象類型所占字節(jié)數(shù));
  2. 在分配的內(nèi)存上調(diào)用對象的構(gòu)造函數(shù),完成初始化。

1. 基本語法:單個對象的創(chuàng)建

#include <iostream>
using namespace std;

class Object {
public:
    int value;
    Object(int v) : value(v) {  // 構(gòu)造函數(shù)
        cout << "Object構(gòu)造:value = " << value << endl;
    }
    ~Object() {  // 析構(gòu)函數(shù)
        cout << "Object析構(gòu):value = " << value << endl;
    }
};

int main() {
    // 用new創(chuàng)建單個Object對象,自動調(diào)用構(gòu)造函數(shù)
    Object* obj = new Object(10);  // 輸出:Object構(gòu)造:value = 10
    cout << "對象的值:" << obj->value << endl;  // 輸出:10
    
    // 用delete銷毀對象,自動調(diào)用析構(gòu)函數(shù)
    delete obj;  // 輸出:Object析構(gòu):value = 10
    obj = nullptr;  // 避免野指針
    return 0;
}

這里的new Object(10)實際執(zhí)行了:

  • 分配sizeof(Object)字節(jié)的內(nèi)存(假設(shè)int占4字節(jié),則總大小為4字節(jié));
  • 調(diào)用Object::Object(10),將內(nèi)存初始化為一個“有意義的對象”。

2. 數(shù)組的創(chuàng)建:new[]與元素初始化

當(dāng)需要創(chuàng)建多個同類型對象時,需使用new[](數(shù)組形式的new),其語法為:

類型* 指針 = new 類型[數(shù)量]{初始化列表};

new[]的工作流程與單個對象類似,但會為數(shù)組中的每個元素調(diào)用構(gòu)造函數(shù):

int main() {
    // 創(chuàng)建包含3個Object的數(shù)組,每個元素調(diào)用構(gòu)造函數(shù)
    Object* arr = new Object[3]{1, 2, 3};  
    // 輸出:
    // Object構(gòu)造:value = 1
    // Object構(gòu)造:value = 2
    // Object構(gòu)造:value = 3
    
    // 訪問數(shù)組元素
    for (int i = 0; i < 3; i++) {
        cout << "arr[" << i << "].value = " << arr[i].value << endl;
    }
    
    // 釋放數(shù)組,需用delete[](而非delete)
    delete[] arr;  
    // 輸出:
    // Object析構(gòu):value = 3
    // Object析構(gòu):value = 2
    // Object析構(gòu):value = 1
    arr = nullptr;
    return 0;
}

關(guān)鍵注意new[]分配的數(shù)組必須用delete[]釋放,否則會導(dǎo)致“部分元素析構(gòu)函數(shù)未被調(diào)用”——delete[]會記錄數(shù)組長度,逐個調(diào)用元素的析構(gòu)函數(shù),而delete僅調(diào)用首個元素的析構(gòu)函數(shù),造成內(nèi)存泄漏(尤其當(dāng)對象包含動態(tài)資源時)。

3. 內(nèi)存分配失敗的處理:異常與nothrow

默認情況下,new分配內(nèi)存失敗時會拋出std::bad_alloc異常(需包含<new>頭文件)。若希望失敗時返回nullptr而非拋出異常,可使用nothrow版本:

#include <iostream>
#include <new>  // 包含nothrow定義
using namespace std;

int main() {
    // 嘗試分配極大內(nèi)存(可能失敗)
    int* p1 = new int[1000000000000];  // 失敗時拋出bad_alloc異常
    int* p2 = new(nothrow) int[1000000000000];  // 失敗時返回nullptr
    
    if (p2 == nullptr) {
        cout << "內(nèi)存分配失??!" << endl;  // 此句可能執(zhí)行
    } else {
        delete[] p2;
    }
    return 0;
}

實際開發(fā)中,需根據(jù)場景選擇異常處理方式:對關(guān)鍵流程,異常能更及時地暴露問題;對非關(guān)鍵流程,nothrow可簡化錯誤判斷。

三、delete的工作原理與語法形式

delete的核心功能是“銷毀堆上的對象并釋放內(nèi)存”,其操作可分解為:

  1. 調(diào)用對象的析構(gòu)函數(shù),清理對象持有的資源(如動態(tài)內(nèi)存、文件句柄等);
  2. 調(diào)用operator delete函數(shù)釋放原始內(nèi)存(歸還給操作系統(tǒng)或內(nèi)存池)。

1. 單個對象的銷毀

對于new創(chuàng)建的單個對象,用delete銷毀:

Object* obj = new Object(5);  // 分配+構(gòu)造
delete obj;  // 析構(gòu)+釋放

若對象持有動態(tài)資源(如內(nèi)部有new分配的指針),析構(gòu)函數(shù)的作用尤為關(guān)鍵:

class ResourceHolder {
private:
    int* data;  // 動態(tài)資源
public:
    ResourceHolder(int size) {
        data = new int[size];  // 分配內(nèi)部資源
        cout << "分配了" << size << "個int的資源" << endl;
    }
    ~ResourceHolder() {
        delete[] data;  // 析構(gòu)時釋放內(nèi)部資源
        cout << "釋放了內(nèi)部資源" << endl;
    }
};

int main() {
    ResourceHolder* rh = new ResourceHolder(10);  // 分配+構(gòu)造(內(nèi)部資源被分配)
    delete rh;  // 先調(diào)用析構(gòu)(釋放內(nèi)部資源),再釋放rh本身的內(nèi)存
    return 0;
}

若此處誤用free(rh)(C語言函數(shù)),則~ResourceHolder()不會被調(diào)用,data指向的內(nèi)存永遠無法釋放,造成內(nèi)存泄漏。這正是delete必須與new配對的原因——它確保了析構(gòu)函數(shù)的執(zhí)行。

2. 數(shù)組的銷毀:delete[]的特殊性

對于new[]創(chuàng)建的數(shù)組,delete[]會:

  • 先確定數(shù)組長度(new[]會在內(nèi)存塊頭部額外存儲長度信息);
  • 按“從后往前”的順序調(diào)用每個元素的析構(gòu)函數(shù);
  • 釋放整個數(shù)組的內(nèi)存。

若用delete替代delete[],編譯器可能只調(diào)用首個元素的析構(gòu)函數(shù),后續(xù)元素的資源(如動態(tài)內(nèi)存)將泄漏。例如:

// 錯誤示例:用delete釋放new[]創(chuàng)建的數(shù)組
ResourceHolder* arr = new ResourceHolder[2]{10, 20};  // 2個對象,各分配資源
delete arr;  // 僅調(diào)用第1個元素的析構(gòu)函數(shù),第2個元素的data內(nèi)存泄漏!

四、特殊用法:placement new(定位new)

placement new是一種特殊形式的new,允許在已分配的內(nèi)存上構(gòu)造對象,而不重新分配內(nèi)存。

其語法為:

new (內(nèi)存地址) 類型(構(gòu)造參數(shù));

它的核心場景是“內(nèi)存池”——預(yù)先分配一大塊內(nèi)存,后續(xù)在上面反復(fù)創(chuàng)建/銷毀對象,避免頻繁分配釋放內(nèi)存的開銷。

#include <iostream>
#include <new>  // placement new需包含此頭文件
using namespace std;

class Test {
public:
    int x;
    Test(int val) : x(val) {
        cout << "Test構(gòu)造:x = " << x << endl;
    }
    ~Test() {
        cout << "Test析構(gòu):x = " << x << endl;
    }
};

int main() {
    // 預(yù)先分配一塊足夠大的內(nèi)存(大小為Test對象的大?。?
    char* buffer = new char[sizeof(Test)];  // 僅分配內(nèi)存,不構(gòu)造對象
    
    // 在buffer指向的內(nèi)存上構(gòu)造Test對象(placement new)
    Test* t = new (buffer) Test(100);  // 輸出:Test構(gòu)造:x = 100
    cout << "對象的值:" << t->x << endl;  // 輸出:100
    
    // 銷毀對象:placement new沒有對應(yīng)的delete,需手動調(diào)用析構(gòu)函數(shù)
    t->~Test();  // 輸出:Test析構(gòu):x = 100
    
    // 釋放預(yù)先分配的內(nèi)存(用delete[],因為buffer是new[]分配的)
    delete[] buffer;
    return 0;
}

注意placement new不分配內(nèi)存,因此無需(也不能)用delete釋放對象——需顯式調(diào)用析構(gòu)函數(shù),再釋放原始內(nèi)存塊。

五、與malloc()/free()的本質(zhì)區(qū)別

特性new/deletemalloc()/free()
操作對象針對“對象”(分配+構(gòu)造,析構(gòu)+釋放)針對“原始內(nèi)存塊”(僅分配/釋放)
類型檢查自動匹配類型,返回對應(yīng)類型指針返回void*,需手動強轉(zhuǎn)
失敗處理默認拋異常,nothrow版本返回nullptr返回nullptr
數(shù)組支持new[]/delete[]自動處理長度需手動計算總字節(jié)數(shù)(n * sizeof(類型))
重載支持可重載operator new/operator delete不可重載

關(guān)鍵原則new分配的內(nèi)存必須用delete釋放,malloc()分配的內(nèi)存必須用free()釋放,不可混用——否則可能導(dǎo)致析構(gòu)函數(shù)不執(zhí)行或內(nèi)存管理混亂。

六、常見錯誤與最佳實踐

1.混用newdelete[]

  • 例如用delete釋放new[]創(chuàng)建的數(shù)組,會導(dǎo)致部分元素析構(gòu)函數(shù)未調(diào)用,造成資源泄漏。
  • 解決:嚴(yán)格遵循“newdeletenew[]delete[]”。

2.重復(fù)釋放內(nèi)存

  • 對同一塊內(nèi)存調(diào)用多次delete,會導(dǎo)致堆損壞(Heap Corruption),程序可能崩潰或行為異常。
  • 解決:釋放后將指針置為nullptrdelete nullptr是安全的,無副作用)。

3.野指針操作

  • 釋放內(nèi)存后未置空指針,后續(xù)誤操作該指針(如訪問、再次釋放)會導(dǎo)致未定義行為。
  • 解決:釋放后立即將指針設(shè)為nullptr。

4.忽略異常處理

  • 默認new分配失敗會拋異常,若未捕獲,程序會直接終止。
  • 解決:關(guān)鍵場景中使用try-catch捕獲bad_alloc,或用nothrow版本顯式判斷nullptr。

5.過度依賴手動管理

  • 復(fù)雜程序中,手動調(diào)用new/delete易因邏輯疏漏導(dǎo)致內(nèi)存泄漏。
  • 解決:優(yōu)先使用C++11引入的智能指針(std::unique_ptrstd::shared_ptr),它們通過RAII(資源獲取即初始化)機制自動管理內(nèi)存生命周期。

newdelete是C++動態(tài)內(nèi)存管理的基石,它們超越了單純的內(nèi)存操作,深度整合了對象的構(gòu)造與析構(gòu),是面向?qū)ο缶幊痰暮诵闹?。理解其工作原理(分?構(gòu)造、析構(gòu)+釋放)、掌握數(shù)組與單個對象的處理差異、規(guī)避常見錯誤,是寫出健壯C++程序的前提。

在現(xiàn)代C++開發(fā)中,雖然智能指針已大幅減少了手動使用new/delete的需求,但理解這對操作符的本質(zhì),仍是掌握內(nèi)存管理的關(guān)鍵——它不僅關(guān)乎代碼的正確性,更體現(xiàn)了對C++對象模型和資源管理哲學(xué)的理解。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • QML與C++交互的實現(xiàn)步驟

    QML與C++交互的實現(xiàn)步驟

    本文主要介紹了QML與C++交互的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言中QString與QByteArray互相轉(zhuǎn)換的方法

    C語言中QString與QByteArray互相轉(zhuǎn)換的方法

    本文主要介紹了C語言中QString與QByteArray互相轉(zhuǎn)換的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • cocos2dx實現(xiàn)橡皮擦效果以及判斷是否擦除完畢

    cocos2dx實現(xiàn)橡皮擦效果以及判斷是否擦除完畢

    這篇文章主要為大家詳細介紹了cocos2dx實現(xiàn)橡皮擦效果以及判斷是否擦除完畢,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • C語言實現(xiàn)小貓釣魚游戲

    C語言實現(xiàn)小貓釣魚游戲

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)小貓釣魚游戲,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Cocos2d-x中獲取系統(tǒng)時間和隨機數(shù)實例

    Cocos2d-x中獲取系統(tǒng)時間和隨機數(shù)實例

    這篇文章主要介紹了Cocos2d-x中獲取系統(tǒng)時間和隨機數(shù)實例,本文代碼含有大量注釋來講解獲取系統(tǒng)時間和隨機數(shù)的方法,需要的朋友可以參考下
    2014-09-09
  • C語言之單鏈表的插入、刪除與查找

    C語言之單鏈表的插入、刪除與查找

    本篇文章主要介紹了從單鏈表的創(chuàng)建、遍歷到節(jié)點的插入、刪除與查找功能的實現(xiàn),有需要的朋友可以參考下
    2015-07-07
  • C++可變參數(shù)模板深入深剖

    C++可變參數(shù)模板深入深剖

    個可變參數(shù)模板(variadic template)就是一個接受可變數(shù)目參數(shù)的函數(shù)模板或類模板,下面這篇文章主要給大家介紹了關(guān)于C++可變參數(shù)模板的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-10-10
  • C++示例詳解Prim算法與優(yōu)先隊列

    C++示例詳解Prim算法與優(yōu)先隊列

    這篇文章介紹了C++ Prim算法、優(yōu)先隊列,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C++基于socket編程實現(xiàn)聊天室功能

    C++基于socket編程實現(xiàn)聊天室功能

    這篇文章主要介紹了C++基于socket編程實現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • C++?路徑中./、../、/代表的含義

    C++?路徑中./、../、/代表的含義

    這篇文章主要介紹了C++?路徑中./、../、/代表的含義,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12

最新評論