棧/堆/static/虛表

在 C++ 里,棧空間主要用來存放局部變量、函數調用信息等。下面為你介紹棧空間在 C++ 里的運用方式。

1. 局部變量的使用

在函數內部定義的變量會被存于棧空間,當函數執行結束,這些變量會自動被銷毀。

#include <iostream>void exampleFunction() {// 定義一個局部變量,存于棧空間int localVar = 10;std::cout << "Local variable value: " << localVar << std::endl;
}int main() {exampleFunction();return 0;
}

2. 函數調用棧

每次調用函數時,系統會在棧上為該函數創建一個棧幀,用來保存函數的局部變量、參數、返回地址等信息。函數返回時,對應的棧幀會被銷毀。

#include <iostream>void func2(int value) {std::cout << "Value in func2: " << value << std::endl;
}void func1() {int localVar = 20;func2(localVar);
}int main() {func1();return 0;
}

3. 遞歸調用

遞歸函數是在函數內部調用自身,每次遞歸調用都會在棧上創建新的棧幀。要注意遞歸深度,防止棧溢出。

#include <iostream>// 遞歸計算階乘
int factorial(int n) {if (n == 0 || n == 1) {return 1;}return n * factorial(n - 1);
}int main() {int num = 5;std::cout << "Factorial of " << num << " is: " << factorial(num) << std::endl;return 0;
}

棧空間使用的注意事項

  • 棧溢出:若棧空間使用過多,例如遞歸過深或者局部變量占用空間過大,就會引發棧溢出錯誤。
  • 生命周期:棧上的變量生命周期局限于定義它的代碼塊,出了代碼塊就會被銷毀。

在 C++ 中,堆空間用于動態分配內存,可在程序運行時根據需要分配和釋放內存。下面詳細介紹堆空間的使用方法。

1. 使用?new?和?delete?操作符進行內存分配和釋放

  • 分配單個對象:使用?new?操作符為單個對象分配內存,使用?delete?操作符釋放內存。
#include <iostream>int main() {// 在堆上分配一個 int 類型的對象int* ptr = new int;*ptr = 42;std::cout << "Value: " << *ptr << std::endl;// 釋放堆上的內存delete ptr;return 0;
}
  • 分配數組:使用?new[]?操作符為數組分配內存,使用?delete[]?操作符釋放內存。
#include <iostream>int main() {// 在堆上分配一個包含 5 個 int 元素的數組int* arr = new int[5];for (int i = 0; i < 5; ++i) {arr[i] = i;}// 輸出數組元素for (int i = 0; i < 5; ++i) {std::cout << arr[i] << " ";}std::cout << std::endl;// 釋放堆上的數組內存delete[] arr;return 0;
}

2. 使用智能指針管理堆內存

為了避免手動管理內存帶來的內存泄漏問題,C++ 提供了智能指針。常用的智能指針有?std::unique_ptrstd::shared_ptr?和?std::weak_ptr

  • std::unique_ptr:獨占所指向的對象,同一時間只能有一個?std::unique_ptr?指向該對象。
#include <iostream>
#include <memory>int main() {// 使用 std::unique_ptr 管理堆上的 int 對象std::unique_ptr<int> ptr = std::make_unique<int>(42);std::cout << "Value: " << *ptr << std::endl;// 不需要手動釋放內存,std::unique_ptr 會在離開作用域時自動釋放return 0;
}
  • std::shared_ptr:多個?std::shared_ptr?可以共享同一個對象,使用引用計數來管理對象的生命周期。
#include <iostream>
#include <memory>int main() {// 使用 std::shared_ptr 管理堆上的 int 對象std::shared_ptr<int> ptr1 = std::make_shared<int>(42);std::shared_ptr<int> ptr2 = ptr1;std::cout << "Value: " << *ptr2 << std::endl;// 當所有指向該對象的 std::shared_ptr 都被銷毀時,對象會自動釋放return 0;
}

3. 自定義類對象的堆內存管理

在自定義類中,需要注意析構函數的實現,確保在對象銷毀時正確釋放堆上的內存。

#include <iostream>class MyClass {
private:int* data;
public:MyClass(int value) {// 在構造函數中分配堆內存data = new int(value);}~MyClass() {// 在析構函數中釋放堆內存delete data;}int getValue() const {return *data;}
};int main() {MyClass obj(42);std::cout << "Value: " << obj.getValue() << std::endl;return 0;
}

堆空間使用的注意事項

  • 內存泄漏:如果使用?new?分配了內存,但沒有使用?delete?或?delete[]?釋放,或者智能指針管理不當,會導致內存泄漏。
  • 懸空指針:釋放內存后,指針仍然指向原來的內存地址,使用這樣的指針會導致未定義行為。

4.C/C++ 中static的作用

  • 靜態局部變量:在函數內部用static修飾的局部變量,存儲在全局數據區而非棧區。它的生命周期貫穿整個程序運行期間,在程序執行到其聲明處時首次初始化,之后的函數調用不再初始化;若未顯式初始化,會自動初始化為 0 。其作用域仍在定義它的函數內部。常用于記錄函數調用次數或狀態
  • 靜態全局變量:在全局變量前加static,該變量存儲在全局數據區,作用域為聲明它的文件,其他文件即使使用extern聲明也無法訪問。可提高程序的封裝性,防止全局變量被意外修改,還能避免多文件項目中不同文件同名全局變量的命名沖突。比如在一個多人協作的大型項目中,每個源文件里的靜態全局變量只在本文件內有效,不同文件可使用相同變量名。
  • 靜態函數:被static修飾的函數只能在聲明它的文件中可見和調用,不能被其他文件使用。有助于提高程序的封裝性,減少函數被其他文件錯誤調用的風險
  • 類的靜態數據成員:在類內數據成員聲明前加static,該數據成員為類的所有對象共享,在程序中只有一份拷貝,存儲在全局數據區。
  • 類的靜態成員函數:用static修飾的類成員函數,屬于類本身而非類的對象,沒有this指針,不能直接訪問非靜態成員變量和非靜態成員函數。可在創建對象前調用,常作為工具函數或用于訪問靜態數據成員。

--------------------------------------------------------------------------------------------------------------------------------------關于一個函數的地址這里可以提到的是。函數名就是一個函數的地址!但是不能查地址的時候忽略作用域

關于函數指針問題:typedef void (*PluginFunction)();首先PluginFunction它是這個指針的別名,最后的一個括號說明這個指針可以用于沒有參數的函數!

#include <iostream>// 定義一個插件函數
void pluginFunction() {std::cout << "This is a plugin function." << std::endl;
}// 使用函數指針類型表示插件函數類型
typedef void (*PluginFunction)();// 主程序加載插件并調用插件函數
void loadAndCallPlugin(PluginFunction func) {func();
}int main() {loadAndCallPlugin(pluginFunction);return 0;
}

從這個圖也可以看出虛表也是存在于常量區代碼段的位置!

5.多繼承的虛表

//多繼承的虛函數表
class Base1 {
public:virtual void func1() { std::cout << "Base1::func1" << std::endl; }virtual void func2() { std::cout << "Base1::func2" << std::endl; }
private:int b1;
};class Base2 {
public:virtual void func1() { std::cout << "Base2::func1" << std::endl; }virtual void func2() { std::cout << "Base2::func2" << std::endl; }
private:int b2;
};class Derive : public Base1, public Base2 {
public:virtual void func1() { std::cout << "Derive::func1" << std::endl; }virtual void func3() { std::cout << "Derive::func3" << std::endl; }
private:int d1;
};

derive內有兩個虛表的原因:分別是Base1內的一個虛表,Base2一個續表,而func3會通過編譯器自動放在一個已有的虛表中。

C++ 編譯器為每個包含虛函數的類生成虛函數表,目的是為了實現運行時多態。當一個類繼承自多個基類,且基類都有虛函數時,該派生類會繼承基類的虛表結構。編譯器通常會復用已有的虛表,將新的虛函數指針添加到合適的虛表中,而不是為每個新虛函數單獨創建一個虛表。這樣可以節省內存空間,并保持虛函數調用機制的一致性。

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/72959.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72959.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72959.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue keepalive學習用法

在Vue中&#xff0c;<keep-alive>的include屬性用于指定需要緩存的組件&#xff0c;其實現方式如下&#xff1a; 1. 基本用法 ? 字符串形式&#xff1a;通過逗號分隔組件名稱&#xff0c;匹配到的組件會被緩存。 <keep-alive include"ComponentA,ComponentB&…

搭建個人博客教程(Hexo)

如何快速搭建一套本地的博客系統呢&#xff1f;這里有一套gitNode.jsHexo的部署方案來進行解決。 安裝git Git 是一款免費開源的分布式版本控制系統&#xff0c;由 Linus Torvalds 于 2005 年為 Linux 內核開發設計。它通過本地倉庫和遠程倉庫實現代碼管理&#xff0c;支持分支…

手撕算法之`vector` 擴容、`string` 分割、鏈表翻轉

手寫常見操作:vector 擴容、string 分割、鏈表翻轉 (一)vector擴容 在 C++ 中,vector 的擴容機制是動態數組實現的核心特性,直接關系到性能和內存使用效率。以下是深入剖析: 1. 擴容觸發條件 vector<int> v; v.push_back(1); // 當 size() == capacity() 時觸發…

鴻蒙NEXT開發問題大全(不斷更新中.....)

目錄 問題1&#xff1a;鴻蒙NEXT獲取華為手機的udid ?問題2&#xff1a;[Fail]ExecuteCommand need connect-key? 問題3&#xff1a;測試時如何安裝app包 問題1&#xff1a;鴻蒙NEXT開發獲取華為手機的udid hdc -t "設備的序列號" shell bm get --udid 問題2&…

LiteratureReading:[2016] Enriching Word Vectors with Subword Information

文章目錄 一、文獻簡明&#xff08;zero&#xff09;二、快速預覽&#xff08;first&#xff09;1、標題分析2、作者介紹3、引用數4、摘要分析&#xff08;1&#xff09;翻譯&#xff08;2&#xff09;分析 5、總結分析&#xff08;1&#xff09;翻譯&#xff08;2&#xff09;…

ZMC600E,多核異構如何成就機器人精準控制?

ZMC600E主站控制器憑借其多核異構處理器的強大性能&#xff0c;實現了高算力與高實時性的完美平衡&#xff0c;讓機器人動作流暢、精準無誤。接下來&#xff0c;讓我們深入了解其內核結構的奧秘。 在ZMC600E主站控制器控制機器人的時候&#xff0c;可以精準的控制機器人執行各種…

一文掌握 PostgreSQL 的各種指令(PostgreSQL指令備忘)

引言 PostgreSQL 作為一款功能強大、開源的關系型數據庫管理系統&#xff08;RDBMS&#xff09;&#xff0c;以其高擴展性、SQL 標準兼容性以及豐富的功能特性&#xff0c;成為企業級應用的首選數據庫之一。無論是開發、運維還是數據分析&#xff0c;掌握 PostgreSQL 的核心指…

fastadmin后臺管理員日志指定方法不記錄

做的訂單提醒,只要在線會把日志自動存儲進去,這個又是每30s執行一次,數據庫沒多久就爆掉了,最終找到一個處理方法,可能不是最好的,僅供大家參考 具體位置: application/admin/model/AdminLog.php里面的$ignoreRegex方法 protected static $ignoreRegex [/^(.*)\/(selectpage…

Redis Sentinel(哨兵模式)高可用性解決方案

一、概述 Redis Sentinel&#xff08;哨兵模式&#xff09;是Redis的高可用性&#xff08;High Availability, HA&#xff09;解決方案&#xff0c;它通過哨兵系統和Redis實例的協同工作&#xff0c;確保了Redis服務的高可用性和數據的持久性。哨兵系統由一個或多個哨兵進程組…

密碼學(Public-Key Cryptography and Discrete Logarithms)

Public-Key Cryptography and Discrete Logarithms Discrete Logarithm 核心概念&#xff1a;離散對數是密碼學中一個重要的數學問題&#xff0c;特別是在有限域和循環群中。它基于指數運算在某些群中是單向函數這一特性。也就是說&#xff0c;給定一個群 G G G和一個生成元 …

tcp 通信在wifi 下會出現內容錯誤嗎?

TCP通信在WiFi下可能會出現內容錯誤。TCP&#xff08;Transmission Control Protocol&#xff0c;傳輸控制協議&#xff09;是一種面向連接的、可靠的、基于字節流的傳輸層通信協議。在WiFi環境下&#xff0c;由于信號干擾、信號衰減、多徑傳播等因素&#xff0c;可能會造成數據…

JVM OOM問題如何排查和解決

在 Java 開發中&#xff0c;JVM OOM&#xff08;OutOfMemoryError&#xff09;問題通常是指程序運行時&#xff0c;JVM 無法為對象分配足夠的內存空間&#xff0c;導致發生內存溢出的錯誤。這個問題往往和內存的配置、內存泄漏、或者資源過度使用等因素有關。 1. OOM 錯誤類型…

深入解析音頻編解碼器(Audio CODEC):硬件、接口與驅動開發

音頻編解碼器&#xff08;Audio CODEC&#xff09;是音頻處理系統中的核心組件&#xff0c;負責 模擬信號與數字信號的相互轉換&#xff0c;廣泛應用于 智能音箱、嵌入式系統、消費電子產品 等設備。本篇文章將從 硬件結構、接口解析、驅動開發 和 軟件配置 等方面&#xff0c;…

【QGIS_Python】在QGIS的Python控制臺生成SHP格式點數據并顯示標注

參考文章&#xff1a; 「GIS教程」使用DeepSeek輔助QGIS快速制圖 | 麻辣GIS 示例代碼說明&#xff1a;使用參考文章中的省會城市坐標點&#xff0c;左側增加一列城市序號code, 圖層標注顯示 code 城市名稱&#xff0c;同時在指定路徑下生成對應SHP格式點數據。 import os fr…

deepSpeed多機多卡訓練服務器之間,和服務器內兩個GPU是怎么通信

DeepSpeed 在多機多卡訓練時,主要依賴 NCCL 和 PyTorch Distributed 進行通信。具體來說,分為服務器之間和服務器內兩種情況: 1. 服務器之間的通信(跨節點通信) DeepSpeed 采用 NCCL(NVIDIA Collective Communications Library)作為主要的通信后端,結合 PyTorch Distr…

k8s-coredns-CrashLoopBackOff 工作不正常

本文作者&#xff1a; slience_me 問題描述 # 問題描述 # rootk8s-node1:/home/slienceme# kubectl get pods --all-namespaces # NAMESPACE NAME READY STATUS RESTARTS AGE # kube-flannel kube-flannel-ds-66bcs …

新能源電站系統建設提速!麒麟信安操作系統驅動光伏風電雙領域安全升級

在全球能源結構加速向清潔能源轉型的背景下&#xff0c;新能源電站建設正如火如荼地展開&#xff0c;麒麟信安操作系統為光伏與風電領域提供了穩定可靠的底座支持&#xff0c;目前已在中電乾陽光伏、遼寧鐵嶺風電場、清河光伏、鑫田茨溝風電場、連山風電場等新能源場站落地應用…

Oracle 19c 子分區表索引測試

一、建表語句放在最后&#xff0c;方便查看 二、創建各類索引 --創建本地的主鍵約束&#xff0c;但必須加上分區鍵、子分區鍵MT_O_CODE,M_YMD alter table MS_DMG.A_RED drop constraint MGR_PK_AREAD ; alter table MS_DMG.A_RED add constraint MGR_PK_AREAD primary key …

Linux Vim 寄存器 | 從基礎分類到高級應用

注&#xff1a;本文為 “vim 寄存器” 相關文章合輯。 英文引文&#xff0c;機翻未校。 中文引文&#xff0c;略作重排。 未整理去重&#xff0c;如有內容異常&#xff0c;請看原文。 Registers 寄存器 Learning Vim registers is like learning algebra for the first ti…

【Java/數據結構】隊列(Quque)

本博客將介紹隊列的相關知識&#xff0c;包括基于數組的普通隊列&#xff0c;基于鏈表的普通隊列&#xff0c;基于數組的雙端隊列&#xff0c;基于鏈表的雙端隊列&#xff0c;但不包括優先級隊列&#xff08;PriorityQueue&#xff09;&#xff0c;此數據結構將單獨發一篇博客&…