日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

酒店房间和 C++ 局部变量的作用域

發(fā)布時(shí)間:2023/12/13 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 酒店房间和 C++ 局部变量的作用域 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文由 伯樂在線 - 菜鳥浮出水 翻譯自 StackOverflow。歡迎加入 技術(shù)翻譯小組。轉(zhuǎn)載請(qǐng)參見文章末尾處的要求。

問題:Can a local variable’s memory be accessed outside its scope? 有一段局部變量的內(nèi)存,可以從其范圍之外訪問它么?

如下代碼:

1 2 3 4 5 6 7 8 9 10 11 12 13 int *foo() { ????int a = 5; ????return &a; } int main() { ????int *p = foo(); ????cout << *p; ????*p = 8; ????cout << *p; }

這樣的代碼可以正常執(zhí)行,而且沒有任何運(yùn)行時(shí)的異常!

輸出是 5 8

這是怎么回事?難道局部變量在函數(shù)外也可以被訪問嗎?

?

來自微軟資深軟件工程師?Eric Lippert?的最佳答案(3200+贊):

你在酒店里租了一間房。你把一本書放進(jìn)了桌子的第一個(gè)抽屜里,然后就去睡覺了。當(dāng)你第二天早上醒來時(shí),你假裝忘記去還鑰匙了。你偷了房間的鑰匙!

一周之后,你回到了酒店,但沒有入住,你用偷來的鑰匙溜進(jìn)了你上次入住的房間,并查看了那個(gè)抽屜。你的書還在那里。是不是很令人吃驚!

這是怎么回事呢?難道一個(gè)酒店房間的抽屜不是應(yīng)該無法被一個(gè)沒有入住這個(gè)房間的人看到嗎?

好吧,明顯的是,這種情況在真實(shí)世界中當(dāng)然會(huì)發(fā)生。在你不入住這個(gè)房間的時(shí)候,這里面沒有任何神秘的力量把你的書弄消失掉,也沒有魔法能夠阻止你用偷來的鑰匙進(jìn)入房間。

酒店的管理規(guī)章里沒有要求拿走你的書。你也沒有跟他們說如果你落下了一本書,他們可以幫你撕毀它。如果你用偷來的鑰匙非法進(jìn)入了你上次的房間,并且沒有被酒店的安保系統(tǒng)發(fā)現(xiàn)。你也沒有跟他們說如果你之后嘗試溜進(jìn)房間,他們應(yīng)該阻止你。不過事實(shí)上,你確實(shí)簽了一份協(xié)議規(guī)定你保證不會(huì)偷偷溜回房間。只不過你打破了協(xié)議。

在這種情況下任何事情都有可能發(fā)生。如果你運(yùn)氣好的話,那本書可能還在那里。其他人的書也可能在那個(gè)抽屜里而你的書則被丟進(jìn)了酒店的火爐里。也可能當(dāng)你溜進(jìn)去的時(shí)候正好有個(gè)人在把你的書撕成碎片。酒店可能把那張桌子連帶你的書都移走了,而把一個(gè)衣柜放在那里。這家酒店也可能正好要被拆除,換成一個(gè)足球場(chǎng),在你溜來溜去的時(shí)候。你可能會(huì)在一場(chǎng)爆破中死去。

當(dāng)你離開酒店而偷了房間的鑰匙的時(shí)候,你不知道將會(huì)發(fā)生什么。你放棄了去生活在一個(gè)可靠的,安全的世界里,因?yàn)槟氵x擇去打破系統(tǒng)的規(guī)則。

C++不是一門安全的語言。你可以非常輕松就打破這個(gè)系統(tǒng)的規(guī)則。如果你嘗試去做一些非法并且愚蠢的事情,比如你回到那個(gè)你已經(jīng)不入住的房間,并想要去查看那張也許已經(jīng)不存在的桌子。C++不會(huì)阻止你的。比C++更加安全的語言通過限制你的能力來解決這個(gè)問題,比如通過更加嚴(yán)格的控制房間鑰匙。

【更新】:

我的老天。這個(gè)答案獲得了這么多的關(guān)注。(我不知道為什么,我只是覺得這樣比喻比較有趣, 不過管他呢。)

我認(rèn)為在經(jīng)過了更加技術(shù)性的思考之后更新一下這個(gè)答案是必要的。

編譯器的工作是生成代碼來管理這個(gè)程序數(shù)據(jù)擁有的內(nèi)存。有很多方式來生成管理內(nèi)存的代碼,但是這么多年來有兩個(gè)基本的技術(shù)是必須要知道的。

第一個(gè)是擁有一片長(zhǎng)期存在的區(qū)域,這片存儲(chǔ)區(qū)域里的每一個(gè)字節(jié),他們的生命周期比較長(zhǎng)。生命周期的意思就是它們能夠被程序訪問的時(shí)期。這類內(nèi)存沒辦法提前進(jìn)行預(yù)估。編譯器生成一種叫堆管理器的代碼,它知道如何在需要的時(shí)候動(dòng)態(tài)的分配內(nèi)存,當(dāng)內(nèi)存不再被需要的時(shí)候釋放掉他們。

第二個(gè)是擁有一片短期存在的區(qū)域,這片存儲(chǔ)區(qū)域里的每一個(gè)字節(jié)都可以提前進(jìn)行預(yù)估。而且比較特殊的是,這片區(qū)域的生命周期遵循一種嵌套模式。也就是說,在這片區(qū)域中擁有最長(zhǎng)生命周期的變量,它所分配的內(nèi)存地址被它之后分配的那些生命周期較短的變量所重用。

局部變量就是第二種情況。當(dāng)調(diào)用一個(gè)函數(shù)時(shí),它的局部變量便被生成了。當(dāng)這個(gè)函數(shù)調(diào)用另外一個(gè)函數(shù)時(shí),新函數(shù)的局部變量也被生成了。這些變量會(huì)在第一個(gè)函數(shù)的局部變量之前被釋放掉。這些局部變量的內(nèi)存地址的開始和結(jié)束可以提前被計(jì)算出來。

因?yàn)檫@個(gè)原因,局部變量經(jīng)常被分配到棧數(shù)據(jù)結(jié)構(gòu)里,因?yàn)橐粋€(gè)棧的特點(diǎn)是第一個(gè)入棧的元素將會(huì)最后一個(gè)出棧。

這就好像酒店決定只能按照順序進(jìn)行房間的出租。你沒辦法離開,除非你之前所有房間號(hào)比你大的人都走了。

所以,讓我們來想一下棧的操作過程。在很多操作系統(tǒng)中,每一個(gè)線程都有一個(gè)棧,并且棧的大小是一個(gè)可變的確定大小。當(dāng)你調(diào)用一個(gè)函數(shù)的時(shí)候,相關(guān)的內(nèi)容被壓入棧內(nèi)。當(dāng)你把一個(gè)這個(gè)棧的指針傳出這個(gè)函數(shù)時(shí),就像上面的提問者所干的一樣。那個(gè)指針只是指向全部有效的數(shù)百萬個(gè)字節(jié)內(nèi)存塊的中間。在我們的類比中,當(dāng)你離開酒店的時(shí)候,你只是離開了當(dāng)前被占用的數(shù)字最大的房間。如果沒有人在你之后入住,你又非法地回到了這個(gè)房間。你所有的東西肯定都還在這個(gè)酒店的房間里。

我們用棧作為臨時(shí)存儲(chǔ)因?yàn)樗鼈兎浅A畠r(jià)并且容易實(shí)現(xiàn)。C++的實(shí)現(xiàn)沒有規(guī)定一定要用棧來存儲(chǔ)局部變量,你可以使用堆來存儲(chǔ)它們,不過沒有人這么干,因?yàn)槟菢幼鰰?huì)使得程序變得很慢。

C++也沒有規(guī)定在你離開棧之后需要清掉棧里的內(nèi)容,所以你可以在之后非法地回到棧里找到你之前的內(nèi)容。當(dāng)然編譯器如果生成代碼,一旦你不再使用了就把棧里的所有內(nèi)容都清零,這是完全合法的。不需要再解釋為什么了,因?yàn)檫@樣做代價(jià)非常高。

C++沒有規(guī)定要確保當(dāng)棧變小時(shí),之前有效的內(nèi)存地址依然有效。C++的實(shí)現(xiàn)也允許告訴操作系統(tǒng)“我們已經(jīng)不再需要棧的個(gè)內(nèi)存頁了。除非我說,否則當(dāng)有任何人要訪問這個(gè)之前有效的棧的內(nèi)存頁的時(shí)候拋出一個(gè)異常并結(jié)束程序”。再次,一般的實(shí)現(xiàn)也沒有這么做,因?yàn)檫@么說使程序變慢而且沒有必要。

相反,大多數(shù)時(shí)候,一般的C++實(shí)現(xiàn)允許你犯錯(cuò)然后避免它。直到有一天,一些真正非常令人恐怖的錯(cuò)誤出現(xiàn)了然后把整個(gè)程序弄崩潰了。

這樣做是有問題的。C++里有如此多的規(guī)則而又如此輕易就可以打破它們。我自己就有好多次這樣的經(jīng)歷。更糟的是,這種問題往往是表面的,當(dāng)你發(fā)現(xiàn)內(nèi)存地址沖突了之后去檢查內(nèi)存,卻發(fā)現(xiàn)它們?cè)诤荛L(zhǎng)時(shí)間內(nèi)又是正確的。所以你很難知道到底是哪個(gè)地方出錯(cuò)了。

那些內(nèi)存安全的語言通過限制你的能力來解決這個(gè)問題。在規(guī)范的C#里,沒有任何辦法去獲取一個(gè)局部變量的內(nèi)存地址,然后返回它或者是存儲(chǔ)它等以后再用。你可以獲取一個(gè)局部變量的內(nèi)存地址,但是語言被很好的設(shè)計(jì)了,你不可能在局部變量生命周期之后還能夠使用它。為了取得局部變量的內(nèi)存地址并把它返回,你必須要把編譯器設(shè)置為一個(gè)特殊的不安全的模式,并且在你的程序里寫上“unsafe”關(guān)鍵字。這可以幫助提醒你,你正在做一些不安全的可能會(huì)打破規(guī)則的事情。

更進(jìn)一步閱讀:
當(dāng)C#返回引用時(shí)做了些什么?

http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx

為什么我們用棧來管理內(nèi)存?C#里值的類型是否一直存儲(chǔ)在棧里?虛擬內(nèi)存是如何工作的?以及更多的關(guān)于C#內(nèi)存管理是如何工作的。這里許多文章都對(duì)C++程序員有幫助。

http://blogs.msdn.com/b/ericlippert/archive/tags/memory+management/

總結(jié)

以上是生活随笔為你收集整理的酒店房间和 C++ 局部变量的作用域的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。