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

C++?內(nèi)存管理深入解析

 更新時(shí)間:2025年09月19日 09:26:25   作者:xclic  
C++內(nèi)存管理分棧、堆、全局/靜態(tài)區(qū)等,需手動(dòng)控制動(dòng)態(tài)內(nèi)存分配,通過(guò)new/delete管理對(duì)象生命周期,推薦使用智能指針和RAII原則避免內(nèi)存泄漏、懸空指針等錯(cuò)誤,確保程序安全高效運(yùn)行,本文給大家介紹c++內(nèi)存管理的相關(guān)知識(shí),感興趣的朋友一起看看吧

C++ 內(nèi)存管理是程序設(shè)計(jì)的核心環(huán)節(jié),直接影響程序的性能、穩(wěn)定性和安全性。C++ 不像 Java、Python 等語(yǔ)言有自動(dòng)垃圾回收機(jī)制,而是需要開(kāi)發(fā)者手動(dòng)管理動(dòng)態(tài)內(nèi)存(或通過(guò)智能指針等機(jī)制自動(dòng)管理)。

1、C++ 內(nèi)存分區(qū)

內(nèi)存區(qū)域存儲(chǔ)內(nèi)容生命周期管理方式
棧 (Stack)函數(shù)參數(shù)、局部變量、函數(shù)返回值等自動(dòng)管理。在作用域開(kāi)始時(shí)分配,作用域結(jié)束時(shí)自動(dòng)釋放。編譯器自動(dòng)生成代碼管理,效率極高。
堆/自由存儲(chǔ)區(qū) (Heap/Free Store)動(dòng)態(tài)分配的內(nèi)存手動(dòng)管理。從 new 開(kāi)始到 delete 結(jié)束。程序員顯式控制。分配和釋放速度較慢,容易出錯(cuò)。
全局/靜態(tài)存儲(chǔ)區(qū) (Global/Static)全局變量、靜態(tài)變量(static)、字面量整個(gè)程序運(yùn)行時(shí)。在 main 開(kāi)始前初始化,main 結(jié)束后銷毀。編譯器管理。
常量區(qū) (Constant)字符串字面量和其他常量整個(gè)程序運(yùn)行時(shí)。編譯器管理。通常不可修改。
代碼區(qū) (Code/Text)程序的二進(jìn)制代碼(函數(shù)體)整個(gè)程序運(yùn)行時(shí)。編譯器管理。

圖示:

+-----------------------+
|       棧 (Stack)      | <- 高地址,向下增長(zhǎng)
+-----------------------+
|          ↓            |
|                       |
|          ↑            |
+-----------------------+
|       堆 (Heap)       | <- 低地址,向上增長(zhǎng)
+-----------------------+
| 全局/靜態(tài)區(qū) (Global)   |
+-----------------------+
|   常量區(qū) (Constants)   |
+-----------------------+
|   代碼區(qū) (Code/Text)   |
+-----------------------+ 

2、棧

  • 特點(diǎn)
    • 空間較?。ㄍǔ?MB),由操作系統(tǒng)自動(dòng)分配和釋放,遵循“先進(jìn)后出”(FILO)原則。
    • 分配速度極快(僅需移動(dòng)棧指針),適合存儲(chǔ)短期存在的變量(如函數(shù)內(nèi)的局部變量)。
void stackExample() {
    int x = 10; // `x` 在棧上分配
    std::string name = "Alice"; // `name` 對(duì)象本身在棧上,但其內(nèi)部的動(dòng)態(tài)數(shù)據(jù)可能在堆上
    double data[100]; // 數(shù)組 `data` 在棧上分配(如果100很大,可能導(dǎo)致棧溢出)
} // 作用域結(jié)束,`x`, `name`, `data` 被自動(dòng)銷毀。
   // `std::string` 的析構(gòu)函數(shù)會(huì)被調(diào)用,釋放它可能占用的堆內(nèi)存。

注意:不要返回指向棧內(nèi)存的指針或引用!

int* dangerousFunction() {
    int localVar = 42;
    return &localVar; // 嚴(yán)重錯(cuò)誤!返回后 localVar 已被銷毀,指針懸空。
}

3、堆

  • 特點(diǎn)
    • 空間較大(通常幾 GB),生命周期由開(kāi)發(fā)者控制(需手動(dòng)申請(qǐng)和釋放),分配/釋放速度較慢(涉及內(nèi)存塊查找、鏈表維護(hù)等)。
    • 內(nèi)存地址不連續(xù),頻繁分配/釋放可能產(chǎn)生內(nèi)存碎片。

3.1 動(dòng)態(tài)分配與釋放:new / delete

new 運(yùn)算符完成兩件事:1) 在堆上分配足夠的內(nèi)存;2) 在該內(nèi)存上構(gòu)造對(duì)象(調(diào)用構(gòu)造函數(shù))。
delete 運(yùn)算符也完成兩件事:1) 調(diào)用對(duì)象的析構(gòu)函數(shù);2) 釋放該對(duì)象占用的內(nèi)存。

// 動(dòng)態(tài)分配一個(gè) int,并初始化為 5
int* ptr = new int(5); 
// 動(dòng)態(tài)分配一個(gè) MyClass 對(duì)象,調(diào)用其構(gòu)造函數(shù)
MyClass* objPtr = new MyClass("Name", 10); 
// ... 使用 ptr 和 objPtr ...
// 釋放內(nèi)存
delete ptr;    // 釋放 int
delete objPtr; // 調(diào)用 ~MyClass(),然后釋放內(nèi)存
ptr = nullptr; // 良好實(shí)踐:釋放后立即置空,防止懸空指針
objPtr = nullptr;

3.2 分配/釋放對(duì)象數(shù)組

// 動(dòng)態(tài)分配一個(gè)包含10個(gè)int的數(shù)組
int* arrayPtr = new int[10]; 
// 動(dòng)態(tài)分配3個(gè)MyClass對(duì)象,調(diào)用它們的默認(rèn)構(gòu)造函數(shù)
MyClass* objArrayPtr = new MyClass[3]; 
// ... 使用數(shù)組 ...
// 釋放數(shù)組內(nèi)存。必須使用 delete[]!
delete[] arrayPtr;     // 正確:釋放數(shù)組
delete[] objArrayPtr;  // 正確:調(diào)用每個(gè)元素的析構(gòu)函數(shù),然后釋放內(nèi)存
// delete objArrayPtr; // 災(zāi)難性錯(cuò)誤!行為未定義。只會(huì)調(diào)用第一個(gè)元素的析構(gòu)函數(shù),然后錯(cuò)誤地釋放內(nèi)存。

3.3 new/delete和malloc/free

C++ 提供兩種動(dòng)態(tài)內(nèi)存管理方式:C 語(yǔ)言兼容的 malloc/free,以及 C++ 特有的 new/delete。

重要規(guī)則: 絕對(duì)不要混用! 用 new 分配的內(nèi)存必須用 delete 釋放;用 malloc() 分配的內(nèi)存必須用 free() 釋放。

3.3.1 malloc/free(C 風(fēng)格)

函數(shù)原型

void* malloc(size_t size);  // 分配 size 字節(jié)的內(nèi)存,返回 void*(需強(qiáng)轉(zhuǎn))
void free(void* ptr);       // 釋放 ptr 指向的內(nèi)存(ptr 必須是 malloc 分配的地址)

特點(diǎn)

  • 僅分配內(nèi)存,不調(diào)用對(duì)象的構(gòu)造函數(shù);釋放內(nèi)存時(shí),不調(diào)用析構(gòu)函數(shù)(僅適用于基本類型,不適合類對(duì)象)。
  • 需手動(dòng)計(jì)算內(nèi)存大?。ㄈ?nbsp;malloc(sizeof(int) * 5))。

示例

int* p = (int*)malloc(sizeof(int)); // 分配 int 大小的內(nèi)存(未初始化)
*p = 10;                            // 手動(dòng)賦值
free(p);                            // 釋放內(nèi)存(p 變?yōu)橐爸羔槪ㄗh置空)
p = nullptr;

3.3.2 new/delete(C++ 風(fēng)格)

new/delete 是 C++ 對(duì)動(dòng)態(tài)內(nèi)存管理的增強(qiáng),不僅分配/釋放內(nèi)存,還會(huì)自動(dòng)調(diào)用對(duì)象的構(gòu)造函數(shù)析構(gòu)函數(shù),是管理類對(duì)象的首選方式。

基本用法

// 1. 分配單個(gè)對(duì)象
MyClass* obj = new MyClass(10);  // 調(diào)用 MyClass(int) 構(gòu)造函數(shù)
delete obj;                      // 調(diào)用 MyClass 析構(gòu)函數(shù),釋放內(nèi)存

// 2. 分配數(shù)組(必須用 new[] 和 delete[] 匹配)
MyClass* arr = new MyClass[5];   // 調(diào)用 5 次 MyClass 默認(rèn)構(gòu)造函數(shù)
delete[] arr;                    // 調(diào)用 5 次 MyClass 析構(gòu)函數(shù),釋放數(shù)組

new 的底層原理:
new 操作分兩步:

調(diào)用 operator new(size_t) 分配內(nèi)存(類似 malloc);

在分配的內(nèi)存上調(diào)用對(duì)象的構(gòu)造函數(shù)。

delete 的底層原理:
delete 操作分兩步:

調(diào)用對(duì)象的析構(gòu)函數(shù);

調(diào)用 operator delete(void*) 釋放內(nèi)存(類似 free)。

3.4 常見(jiàn)動(dòng)態(tài)內(nèi)存錯(cuò)誤

3.4.1 內(nèi)存泄漏 (Memory Leak)

分配了內(nèi)存但忘記釋放。
cpp void leak() { int* ptr = new int(100); // ... 使用了 ptr ... return; // 忘記 delete ptr; 內(nèi)存泄漏! }

3.4.2 懸空指針 (Dangling Pointer)

指針指向的內(nèi)存已被釋放。
cpp int* ptr = new int(50); delete ptr; // 內(nèi)存被釋放 *ptr = 10; // 錯(cuò)誤!ptr 現(xiàn)在是懸空指針,解引用它是未定義行為。

3.4.3 雙重釋放 (Double Free)

對(duì)同一塊內(nèi)存釋放兩次。
cpp int* ptr = new int(50); delete ptr; delete ptr; // 災(zāi)難!未定義行為,通常導(dǎo)致程序崩潰。

3.4.4 野指針 (Wild Pointer)

未初始化的指針。
cpp int* ptr; // 野指針,指向隨機(jī)地址 *ptr = 10; // 極度危險(xiǎn)!未定義行為。

4、全局/靜態(tài)區(qū)

特點(diǎn)

  • 全局變量和靜態(tài)變量(包括 static 局部變量)存儲(chǔ)于此,程序啟動(dòng)時(shí)初始化,結(jié)束時(shí)銷毀。
  • static 局部變量?jī)H在首次進(jìn)入函數(shù)時(shí)初始化,生命周期延續(xù)到程序結(jié)束。

示例

int g_var = 10;         // 全局變量,存儲(chǔ)在全局區(qū)
static int s_var = 20;  // 靜態(tài)全局變量,存儲(chǔ)在全局區(qū)
void func() {
    static int s_local = 30; // 靜態(tài)局部變量,存儲(chǔ)在全局區(qū)(僅初始化一次)
}

5、常量區(qū)

  • 特點(diǎn)
    • 存儲(chǔ)字符串常量(如 "hello")和 const 修飾的常量,內(nèi)容只讀(修改會(huì)導(dǎo)致未定義行為)。
  • 示例
const int c_var = 100;   // const 常量,存儲(chǔ)在常量區(qū)
char* str = "hello";     // "hello" 存儲(chǔ)在常量區(qū),str 是棧上的指針

6、常見(jiàn)問(wèn)題

  • new/delete 和 malloc()/free() 有什么區(qū)別?
    • new/delete 關(guān)心對(duì)象生命周期(構(gòu)造/析構(gòu)),而 malloc/free 只關(guān)心內(nèi)存塊。絕對(duì)不要混用。
  • 什么是內(nèi)存泄漏?如何避免?
    • 動(dòng)態(tài)分配的內(nèi)存不再被使用,但未被釋放,導(dǎo)致內(nèi)存浪費(fèi),長(zhǎng)期運(yùn)行可能耗盡內(nèi)存。
  • 避免方法:
    • 優(yōu)先使用棧對(duì)象:讓編譯器自動(dòng)管理生命周期。
    • 使用智能指針:這是現(xiàn)代 C++ 最主要的手段。std::unique_ptr(獨(dú)占所有權(quán))和 std::shared_ptr(共享所有權(quán))會(huì)在析構(gòu)時(shí)自動(dòng)釋放內(nèi)存。
    • 遵循 RAII 原則:將資源(內(nèi)存、文件句柄等)的獲取與對(duì)象的構(gòu)造函數(shù)綁定,釋放與析構(gòu)函數(shù)綁定。
    • 成對(duì)使用 new/delete 和 new[]/delete[]:確保分配和釋放方式匹配。
    • 使用工具檢測(cè):如 Valgrind、AddressSanitizer (ASan)、Visual Studio 診斷工具等。
    • 為什么更推薦使用 std::make_shared 而不是直接 new?
    • 異常安全:如果函數(shù)參數(shù)在表達(dá)式求值過(guò)程中拋出異常,make_shared 能保證已分配的內(nèi)存會(huì)被釋放,而直接 new 可能會(huì)泄漏。
    • 性能:std::make_shared 通常只進(jìn)行一次內(nèi)存分配,同時(shí)容納對(duì)象本身和控制塊(引用計(jì)數(shù)等)。而 shared_ptr(new T(...)) 需要兩次分配(一次給對(duì)象,一次給控制塊)。
  • 如何從 weak_ptr 安全地訪問(wèn)對(duì)象?
    • 使用 lock() 方法。它會(huì)返回一個(gè) std::shared_ptr。如果原始對(duì)象還存在,這個(gè) shared_ptr 是有效的;如果已被釋放,則返回一個(gè)空的 shared_ptr。必須檢查返回值。
std::weak_ptr<MyClass> weak = ...;
if (auto shared = weak.lock()) { // 檢查返回的shared_ptr是否為空
    // 對(duì)象還存在,可以安全使用 shared
    shared->doSomething();
} else {
    // 對(duì)象已被釋放
    std::cout << "Object is gone.\n";
}
  • 什么是懸空指針 (Dangling Pointer) 和野指針 (Wild Pointer)?

懸空指針:指針指向的內(nèi)存已被釋放,但指針本身未被置空。解引用它是未定義行為

int* ptr = new int(10);
delete ptr; // 內(nèi)存釋放
// ptr 現(xiàn)在是懸空指針
*ptr = 20; // 未定義行為!
ptr = nullptr; // 良好實(shí)踐:釋放后立即置空。

野指針:未被初始化的指針,其值是隨機(jī)的垃圾地址。

int* ptr; // 野指針
*ptr = 10; // 極度危險(xiǎn)!未定義行為。
int* ptr2 = nullptr; // 正確:總是初始化指針。
  • delete 和 delete[] 的區(qū)別是什么?混用會(huì)怎樣?

delete:用于釋放 new 分配的單個(gè)對(duì)象。它會(huì)調(diào)用該對(duì)象的析構(gòu)函數(shù)。

delete[]:用于釋放 new[] 分配的對(duì)象數(shù)組。它會(huì)調(diào)用數(shù)組中每個(gè)元素的析構(gòu)函數(shù),然后釋放整塊內(nèi)存。

混用的后果:未定義行為。最常見(jiàn)的后果是程序崩潰。

用 delete 釋放數(shù)組:只會(huì)調(diào)用第一個(gè)元素的析構(gòu)函數(shù),然后錯(cuò)誤地釋放內(nèi)存。

用 delete[] 釋放單個(gè)對(duì)象:會(huì)試圖析構(gòu)多個(gè)不存在的對(duì)象,導(dǎo)致內(nèi)存結(jié)構(gòu)被破壞。

  • 什么是 RAII?它在 C++ 內(nèi)存管理中如何體現(xiàn)?
  • RAII (Resource Acquisition Is Initialization):資源獲取即初始化。是 C++ 最重要的編程理念之一。
  • 核心思想:將資源(內(nèi)存、文件句柄、鎖等)的生命周期與對(duì)象的生命周期綁定。
    • 獲取資源:在對(duì)象的構(gòu)造函數(shù)中完成(例如,std::ifstream 打開(kāi)文件,std::unique_ptr 分配內(nèi)存)。
    • 釋放資源:在對(duì)象的析構(gòu)函數(shù)中完成(例如,std::ifstream 關(guān)閉文件,std::unique_ptr 釋放內(nèi)存)。
  • 優(yōu)勢(shì):無(wú)論函數(shù)是正常返回還是因異常提前退出,局部對(duì)象都會(huì)在離開(kāi)作用域時(shí)被析構(gòu),從而保證資源一定能被釋放。智能指針是 RAII 用于內(nèi)存管理的完美體現(xiàn)。
  • 設(shè)計(jì)一個(gè) unique_ptr,你會(huì)考慮哪些方面?
    • 封裝一個(gè)原生指針作為成員。
    • 刪除拷貝構(gòu)造函數(shù)和拷貝賦值運(yùn)算符= delete)以實(shí)現(xiàn)獨(dú)占語(yǔ)義。
    • 實(shí)現(xiàn)移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值運(yùn)算符std::move)以支持所有權(quán)轉(zhuǎn)移。
    • 析構(gòu)函數(shù)中調(diào)用刪除器(默認(rèn)是 delete)釋放資源。
    • 重載 operator* 和 operator-> 以提供指針式的訪問(wèn)。
    • 提供 release()reset()get() 等成員函數(shù)。
    • (可選)支持自定義刪除器(作為模板參數(shù)的一部分)。

到此這篇關(guān)于C++ 內(nèi)存管理的文章就介紹到這了,更多相關(guān)C++ 內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++  線程(串行 并行 同步 異步)詳解

    C++ 線程(串行 并行 同步 異步)詳解

    這篇文章主要介紹了C++ 線程(串行 并行 同步 異步)詳解的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • C++ cin不同狀態(tài)詳細(xì)講解

    C++ cin不同狀態(tài)詳細(xì)講解

    cin是C++編程語(yǔ)言中的標(biāo)準(zhǔn)輸入流對(duì)象,即istream類的對(duì)象。cin主要用于從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù),這里的標(biāo)準(zhǔn)輸入,指的是終端的鍵盤。此外,cout是流的對(duì)象,即ostream類的對(duì)象,cerr是標(biāo)準(zhǔn)錯(cuò)誤輸出流的對(duì)象,也是ostream類的對(duì)象
    2022-10-10
  • 構(gòu)造函數(shù)不能聲明為虛函數(shù)的原因及分析

    構(gòu)造函數(shù)不能聲明為虛函數(shù)的原因及分析

    構(gòu)造函數(shù)不需要是虛函數(shù),也不允許是虛函數(shù),因?yàn)閯?chuàng)建一個(gè)對(duì)象時(shí)我們總是要明確指定對(duì)象的類型,盡管我們可能通過(guò)實(shí)驗(yàn)室的基類的指針或引用去訪問(wèn)它但析構(gòu)卻不一定,我們往往通過(guò)基類的指針來(lái)銷毀對(duì)象
    2013-10-10
  • C語(yǔ)言中.與->的區(qū)別詳細(xì)解析

    C語(yǔ)言中.與->的區(qū)別詳細(xì)解析

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中.與->區(qū)別的相關(guān)資料,這雖然是個(gè)小問(wèn)題,但有時(shí)候很容易讓人迷惑,因?yàn)橛械臅r(shí)候用混淆了,程序編譯不通過(guò),需要的朋友可以參考下
    2023-06-06
  • C++淺析內(nèi)聯(lián)函數(shù)的使用

    C++淺析內(nèi)聯(lián)函數(shù)的使用

    為了消除函數(shù)調(diào)用的時(shí)空開(kāi)銷,C++ 提供一種提高效率的方法,即在編譯時(shí)將函數(shù)調(diào)用處用函數(shù)體替換,類似于C語(yǔ)言中的宏展開(kāi)。這種在函數(shù)調(diào)用處直接嵌入函數(shù)體的函數(shù)稱為內(nèi)聯(lián)函數(shù)(Inline Function),又稱內(nèi)嵌函數(shù)或者內(nèi)置函數(shù)
    2022-05-05
  • C/C++中I/O進(jìn)階詳解及其作用介紹

    C/C++中I/O進(jìn)階詳解及其作用介紹

    這篇文章主要介紹了C/C++中I/O進(jìn)階詳解及其作用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • C++11 學(xué)習(xí)筆記之std::function和bind綁定器

    C++11 學(xué)習(xí)筆記之std::function和bind綁定器

    這篇文章主要介紹了C++11 學(xué)習(xí)筆記之std::function和bind綁定器,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • 簡(jiǎn)單介紹C++編程中派生類的析構(gòu)函數(shù)

    簡(jiǎn)單介紹C++編程中派生類的析構(gòu)函數(shù)

    這篇文章主要介紹了C++編程中派生類的析構(gòu)函數(shù),析構(gòu)函數(shù)平時(shí)一般使用較少,需要的朋友可以參考下
    2015-09-09
  • Win10下最新版CLion(2020.1.3)安裝及環(huán)境配置教程詳解

    Win10下最新版CLion(2020.1.3)安裝及環(huán)境配置教程詳解

    這篇文章主要介紹了Win10下最新版CLion(2020.1.3)安裝及環(huán)境配置,CLion 是 JetBrains 推出的全新的 C/C++ 跨平臺(tái)集成開(kāi)發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-08-08
  • C++利用靜態(tài)成員或類模板構(gòu)建鏈表的方法講解

    C++利用靜態(tài)成員或類模板構(gòu)建鏈表的方法講解

    這篇文章主要介紹了C++利用靜態(tài)成員或類模板構(gòu)建鏈表的方法講解,鏈表是基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),而在C++中構(gòu)件單鏈表還是稍顯復(fù)雜,需要的朋友可以參考下
    2016-04-04

最新評(píng)論