我有這個非常簡單的代碼:
#include <iostream>
using namespace std;
int main()
{
int *p, *q, u;
{
p = new int(4);
int v = 5;
q = &v;
u= v;
}//End scope 2
cout<< *p << "\n" << *q << "\n" << u;
delete p;
return 0;
}
輸出是:
4
5
5
如果我錯了,請糾正我:) ...
- 如果我理解,
p指向在堆中分配的記憶體空間,該記憶體不會在“結束范圍”受到影響,并且只會在呼叫delete. - 然后
u是 的硬拷貝v,因此實際上在堆疊記憶體中的其他地方存在它的值的副本。 - 另一方面
q指向 的地址v,該地址在堆疊中分配,在離開“范圍 2”時應該被擦除(?),如果是這種情況,為什么列印*q仍然找到正確的值v?
uj5u.com熱心網友回復:
為什么列印 *q 仍然找到正確的 v 值?
對于不再存在的物件,沒有所謂的“正確價值”。
您觀察到您所做的行為是因為程式的行為未定義。你觀察到一種行為;行為可能是其他東西,因為語言不保證這種行為,但行為不是其他東西,因為語言也不保證任何其他行為。
行為可能是以下任何一種:
- 預期的
- 意外
- 你認為“正確”的東西
- 你認為“錯誤”的事情
- 總是相同的行為
- 從來沒有相同的行為
- 看似確定性
- 非確定性
- 隨機的
- 不是隨機的
- 始終是您想要的正確行為,除非您將其部署到生產中并休假
- 上面未列出的任何內容
uj5u.com熱心網友回復:
這是未定義的行為。當代碼退出作用域時,作用域中的資料和變數都會被洗掉。但這并不意味著 RAM 中的記憶體空間被完全擦除。編譯器取消分配該記憶體,以便可以再次使用記憶體,但最后的資料仍保留在那里。所以,如果記憶體沒有分配給別的東西(不一定是你的程式),它仍然會保留最后的資料。在實踐中,這種情況很少發生。但是對于像您的代碼這樣的小片段,由于記憶體資料在取消分配后幾乎立即列印,它可能會顯示正確的資料。
uj5u.com熱心網友回復:
子彈編號 3 顯然是未定義的行為,因為它已經提到過。
1號雖然很有趣。從某種意義上說,您是對的,它將超出范圍,并且在呼叫 delete 時將被銷毀。然而事實證明,該 as-if 規則也可能適用于堆分配。因此,編譯器(主要是現代編譯器)能夠優化新洗掉,只要他們能證明分配的記憶體沒有在被優化的范圍范圍之外使用。在這種情況下:只要使用分配的變數,就好像它是自動變數一樣。
因此,是否應該從您的代碼中洗掉 UB:
#include <iostream>
using namespace std;
int main()
{
int *p;
{
p = new int(4);
int v = 5;
}//End scope 2
cout<< *p << "\n";
delete p;
return 0;
}
事實證明,新的 GCC(用 11.2 測驗)完全忽略了新洗掉對。見這里。
我的觀點是:知道堆疊/堆是好的,但它是實作細節。我建議您也考慮物件的自動/靜態/動態生命周期/存盤持續時間。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/415833.html
標籤:
上一篇:這段代碼與指標有什么關系嗎?
