最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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正是實(shí)現(xiàn)這一功能的關(guān)鍵操作符。

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

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

C語言通過malloc()free()實(shí)現(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)”綁定的機(jī)制,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)實(shí)際執(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

默認(rèn)情況下,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;
}

實(shí)際開發(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)存永遠(yuǎn)無法釋放,造成內(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[],因?yàn)閎uffer是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*,需手動強(qiáng)轉(zhuǎn)
失敗處理默認(rèn)拋異常,nothrow版本返回nullptr返回nullptr
數(shù)組支持new[]/delete[]自動處理長度需手動計(jì)算總字節(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)存管理混亂。

六、常見錯誤與最佳實(shí)踐

1.混用newdelete[]

  • 例如用delete釋放new[]創(chuàng)建的數(shù)組,會導(dǎo)致部分元素析構(gòu)函數(shù)未調(diào)用,造成資源泄漏。
  • 解決:嚴(yán)格遵循“newdelete,new[]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.忽略異常處理

  • 默認(rèn)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_ptr、std::shared_ptr),它們通過RAII(資源獲取即初始化)機(jī)制自動管理內(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)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Qt QFrame的具體使用

    Qt QFrame的具體使用

    本文主要介紹了Qt QFrame的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 基于C++11的threadpool線程池(簡潔且可以帶任意多的參數(shù))

    基于C++11的threadpool線程池(簡潔且可以帶任意多的參數(shù))

    C++11 加入了線程庫,從此告別了標(biāo)準(zhǔn)庫不支持并發(fā)的歷史。然而 c++ 對于多線程的支持還是比較低級,稍微高級一點(diǎn)的用法都需要自己去實(shí)現(xiàn),譬如線程池、信號量等
    2019-04-04
  • Ubuntu 20.04 下安裝配置 VScode 的 C/C++ 開發(fā)環(huán)境(圖文教程)

    Ubuntu 20.04 下安裝配置 VScode 的 C/C++ 開發(fā)環(huán)境(圖文教程)

    這篇文章主要介紹了Ubuntu 20.04 下安裝配置 VScode 的 C/C++ 開發(fā)環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • C語言中帶頭雙向循環(huán)鏈表基本操作的實(shí)現(xiàn)詳解

    C語言中帶頭雙向循環(huán)鏈表基本操作的實(shí)現(xiàn)詳解

    無頭單向非循環(huán)鏈表結(jié)構(gòu)簡單,一般不會單獨(dú)用來存數(shù)據(jù)。而帶頭雙向循環(huán)鏈表的結(jié)構(gòu)較為復(fù)雜,一般用在單獨(dú)存儲數(shù)據(jù)。本文將介紹帶頭雙向循環(huán)鏈表的基本操作,需要的可以參考一下
    2022-11-11
  • 一篇文章帶你使用C語言編寫內(nèi)核

    一篇文章帶你使用C語言編寫內(nèi)核

    內(nèi)核是操作系統(tǒng)最核心的內(nèi)容,主要提供硬件抽象層、磁盤及文件系統(tǒng)控制、多任務(wù)等功能,由于其涉及非常廣泛的計(jì)算機(jī)知識,很少被人們所熟悉,因而披上了一層神秘的面紗
    2021-08-08
  • C++實(shí)現(xiàn)String類的方法詳解

    C++實(shí)現(xiàn)String類的方法詳解

    在C語言中,沒有專門用來表示字符串的類型。雖然C語言為字符串提供了一系列的庫函數(shù),但這些函數(shù)與字符串這個類型是分開的。所以在C++中封裝了一個string類,來幫助我們操作字符串,本文就為大家提供了實(shí)現(xiàn)String類的方法,需要的可以參考一下
    2022-08-08
  • C++中不同類型默認(rèn)轉(zhuǎn)換的規(guī)則和機(jī)制詳解

    C++中不同類型默認(rèn)轉(zhuǎn)換的規(guī)則和機(jī)制詳解

    在C++中,類型轉(zhuǎn)換是一個非常重要的概念,本文將為大家詳細(xì)介紹一下C++中各種默認(rèn)類型轉(zhuǎn)換的規(guī)則和機(jī)制,因?yàn)椴皇煜つJ(rèn)類型轉(zhuǎn)換,真的很容易寫出bug
    2025-11-11
  • 深入探討linux下進(jìn)程的最大線程數(shù)、進(jìn)程最大數(shù)、進(jìn)程打開的文件數(shù)

    深入探討linux下進(jìn)程的最大線程數(shù)、進(jìn)程最大數(shù)、進(jìn)程打開的文件數(shù)

    本篇文章是對linux下進(jìn)程的最大線程數(shù)、進(jìn)程最大數(shù)、進(jìn)程打開的文件數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 詳解C++編程中的重載流插入運(yùn)算符和流提取運(yùn)算符

    詳解C++編程中的重載流插入運(yùn)算符和流提取運(yùn)算符

    這篇文章主要介紹了詳解C++編程中的重載流插入運(yùn)算符和流提取運(yùn)算符,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • C++示例講解初始化列表方法

    C++示例講解初始化列表方法

    這篇文章主要介紹了C++成員初始化列表,除了可以使用構(gòu)造函數(shù)對類成員進(jìn)行初始化之外,C++還提供了另外一種初始化的方法,叫做成員初始化列表。下面來看看文章的詳細(xì)吧,需要的朋友可以參考一下
    2022-07-07

最新評論

喀喇沁旗| 海门市| 呼和浩特市| 金乡县| 舒城县| 平塘县| 绿春县| 固镇县| 兴隆县| 鸡东县| 开阳县| 卓尼县| 大连市| 邢台市| 隆林| 亚东县| 通榆县| 维西| 息烽县| 日照市| 子洲县| 塔河县| 康乐县| 九江县| 新余市| 连南| 景洪市| 漳浦县| 阿瓦提县| 开远市| 衡水市| 湖州市| 平罗县| 忻城县| 威海市| 乐至县| 关岭| 甘南县| 漳州市| 邹城市| 三门峡市|