C++存儲(chǔ)持續(xù)性生命周期原理解析
存儲(chǔ)持續(xù)性(生命周期)
課堂上都講過,變量有生命周期和作用域,類似的在C++中也有存儲(chǔ)持續(xù)性與連接性的概念。什么是自動(dòng)變量,什么是靜態(tài)變量,什么是全局變量?本文就來解答一下。
存儲(chǔ)持續(xù)性說的就是數(shù)據(jù)在內(nèi)存中保留的時(shí)間。
先來看看下面這段代碼是否有問題?
*int getInt() { int a = 1; return &a; }
我們知道函數(shù)調(diào)用和返回在內(nèi)存中對(duì)應(yīng)入棧出棧的過程。這個(gè)函數(shù)將函數(shù)內(nèi)部創(chuàng)建的自動(dòng)變量a的指針作為返回值返回,變量a分配在棧中,當(dāng)函數(shù)返回,這塊內(nèi)存空間出棧被回收,導(dǎo)致返回的指針也就成了懸掛指針,指向了一塊不屬于它的地址。
在Go等一些語言中,這樣的代碼沒有問題,這是因?yàn)樘右輽C(jī)制,在函數(shù)返回時(shí)可以將棧上的變量a逃逸到堆上。但C++沒有逃逸機(jī)制,因此函數(shù)返回時(shí),a的內(nèi)存空間被回收,返回的指針也就成了懸掛指針,指向了一塊不屬于它的地址。
聽上去有了逃逸機(jī)制,就不需要考慮這類問題,為什么C++沒有呢?凡事都有代價(jià),有逃逸機(jī)制就需要有垃圾回收,而垃圾回收不僅復(fù)雜,更是會(huì)占用程序運(yùn)行時(shí)間。而C++選擇犧牲開發(fā)的便利性,以獲得更高的運(yùn)行時(shí)性能。
事實(shí)上,如果想實(shí)現(xiàn)這樣的功能,在C++中也可以使用智能指針來實(shí)現(xiàn)。一些語言中可以無腦使用的功能,在C++中需要一些學(xué)習(xí)門檻,這也是為什么有些語言學(xué)習(xí)曲線陡峭了。但相對(duì)應(yīng)的,學(xué)習(xí)曲線陡峭也是在逼著我們程序員去學(xué)習(xí)更底層原理的知識(shí),只有足夠了解它才能駕馭它,也是這類語言的魅力所在。
C++中的存儲(chǔ)持續(xù)性有4類
- 自動(dòng)存儲(chǔ)持續(xù)性
- 靜態(tài)存儲(chǔ)持續(xù)性
- 動(dòng)態(tài)存儲(chǔ)持續(xù)性
- 線程存儲(chǔ)持續(xù)性 (C++11新增,本文不討論)
自動(dòng)存儲(chǔ)持續(xù)性
上例的代碼中就說明了自動(dòng)存儲(chǔ)持續(xù)性的特點(diǎn):在函數(shù)或代碼塊內(nèi)聲明的變量,在離開代碼塊之后,其內(nèi)存會(huì)被回收。
自動(dòng)變量不會(huì)進(jìn)行自動(dòng)初始化,如果沒有顯示初始化,那么聲明后的變量內(nèi)容可能是隨機(jī)值。
自動(dòng)變量存儲(chǔ)在棧中。
靜態(tài)存儲(chǔ)持續(xù)性
靜態(tài)變量可以在程序運(yùn)行期間一直保持在內(nèi)存中,即便它在函數(shù)或代碼塊中聲明。而且,所有靜態(tài)變量都是在程序開始運(yùn)行時(shí)就進(jìn)入內(nèi)存了,并不需要實(shí)際執(zhí)行到變量聲明處。
靜態(tài)變量存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)。
那么如何聲明靜態(tài)變量呢?
你一定脫口而出 “static”。這并不準(zhǔn)確。
- 如果變量在代碼塊中聲明,那么加上static則聲明為靜態(tài)
- 如果變量在代碼塊外聲明,則無論有沒有static,都是靜態(tài)變量。這時(shí)如果加static,則static則有另外的含義,表示鏈接性為內(nèi)部。
靜態(tài)變量默認(rèn)會(huì)初始化有兩類:靜態(tài)初始化和動(dòng)態(tài)初始化。靜態(tài)初始化又包括零初始化和常量表達(dá)式初始化。
- 零初始化:靜態(tài)變量默認(rèn)會(huì)進(jìn)行零初始化
- 常量表達(dá)式初始化:在編譯期初始化
- 動(dòng)態(tài)初始化:無法在編譯期初始化,則會(huì)在編譯后初始化??赡艿脑虬ǎ罕磉_(dá)式包含動(dòng)態(tài)變量,需要調(diào)用其他文件的函數(shù)所以必須等鏈接后執(zhí)行。
動(dòng)態(tài)存儲(chǔ)持續(xù)性
動(dòng)態(tài)是指用 new 分配的存儲(chǔ)空間,它從new語句執(zhí)行,到delete語句執(zhí)行,期間一直在內(nèi)存中。它存儲(chǔ)在堆內(nèi)存中。
但并不存在“動(dòng)態(tài)變量”,只是將動(dòng)態(tài)分配的地址賦給一個(gè)指針變量。指針本身有他的內(nèi)存空間,但指針的內(nèi)存被回收,并不會(huì)導(dǎo)致new分配的空間被回收。因此,使用new來申請(qǐng)的內(nèi)存空間一定要用delete刪除。
以上就是C++存儲(chǔ)持續(xù)性生命周期原理解析的詳細(xì)內(nèi)容,更多關(guān)于C++存儲(chǔ)持續(xù)性生命周期的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解C++中typedef 和 #define 的區(qū)別
這篇文章主要介紹了C++中typedef 與 #define 的區(qū)別,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09C++中string轉(zhuǎn)換為char*類型返回后亂碼問題解決
這篇文章主要介紹了C++中string轉(zhuǎn)換為char*類型返回后亂碼問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07在std::thread中創(chuàng)建并管理QEventLoop的全面解析
QEventLoop的工作原理可以簡單地理解為一個(gè)無限循環(huán),它會(huì)不斷地檢查是否有新的事件需要處理,如果有,就將事件從事件隊(duì)列中取出,然后找到相應(yīng)的事件處理器進(jìn)行處理,這篇文章主要介紹了在std::thread中創(chuàng)建并管理QEventLoop的全面指南,需要的朋友可以參考下2023-06-06C++設(shè)計(jì)模式編程中使用Bridge橋接模式的完全攻略
這篇文章主要介紹了C++設(shè)計(jì)模式編程中使用Bridge橋接模式的完全攻略,Bridge將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化需要的朋友可以參考下2016-03-03C++分析如何用虛析構(gòu)與純虛析構(gòu)處理內(nèi)存泄漏
虛析構(gòu)和純虛析構(gòu)共性:可以解決父類指針釋放子類對(duì)象,都需要有具體的函數(shù)實(shí)現(xiàn);虛析構(gòu)和純虛析構(gòu)區(qū)別:如果是純虛析構(gòu),該類屬于抽象類,無法實(shí)例化對(duì)象2022-08-08C++中的動(dòng)態(tài)分派在HotSpot?VM中的應(yīng)用小結(jié)
多態(tài)是面向?qū)ο缶幊陶Z言的重要特性,它允許基類的指針或引用指向派生類的對(duì)象,而在具體訪問時(shí)實(shí)現(xiàn)方法的動(dòng)態(tài)綁定,這篇文章主要介紹了C++的動(dòng)態(tài)分派在HotSpot?VM中的重要應(yīng)用,需要的朋友可以參考下2023-09-09wxWidgets實(shí)現(xiàn)無標(biāo)題欄窗口拖動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了wxWidgets實(shí)現(xiàn)無標(biāo)題欄窗口拖動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02