[問題] 請問local變數在離開stack後為何能存取
開發平台(Platform): (Ex: Win10, Linux, ...)
win10/debian
編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
VC2008/gcc
程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔)
#include <stdio.h>
struct StructB
{
int m_nB;
StructB()
{
m_nB = 0;
}
~StructB()
{
printf("~StructB()\n");
}
};
struct StructA
{
StructA()
{
m_pB = NULL;
}
StructB *m_pB;
};
void foo(StructA &p_stA)
{
StructB stB;
stB.m_nB = 1;
p_stA.m_pB = &stB;
}
int main()
{
StructA stA;
foo(stA);
printf("stA.m_pB->m_nB = %d\n", stA.m_pB->m_nB);
printf("stA.m_pB->m_nB = %d\n", stA.m_pB->m_nB); // 連續兩次看結果
return 0;
}
補充說明(Supplement):
今天工作上我看到project code有很明顯的問題如下.
有一個struct其中一個member是一個pointer,
這個struct產生一個member object放在一個class裡面.
而我尋找這個pointer並沒有任何地方去new物件出來,
而是直接在一個function裡面產生一個local變數,
然後把local變數的位址設定給這個pointer.
問題來了, 設定local變數給這個struct的pointer,
然後離開這個function回到上一層stack, local變數不就free掉了嗎?
再去存取這個struct pointer不是應該就會出問題?
但結果沒有, 我用VC debug看程式竟然還能存取到正確的值.
這讓我對以前變數lifecycle學習產生了質疑,
因此我直接寫了上方簡單的程式碼來驗證這件事.
我分別用VC以及gcc在win10/debian底下去執行上面的程式碼,
神奇的事發生了
win10:
第一次printf看到印出的值正確為1, 第二次變為-2.
debain:
兩次都為1.
我確認StructB的解構式已經"先"印出來才印出數值,
為何被free的變數還能存取到他的數值呢?
請版上先進指教, 謝謝。
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.163.153.38 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1617285280.A.419.html
→
04/01 21:57,
3年前
, 1F
04/01 21:57, 1F
推
04/01 21:57,
3年前
, 2F
04/01 21:57, 2F
→
04/01 21:58,
3年前
, 3F
04/01 21:58, 3F
undefined behavior?
※ 編輯: Keitaro (1.163.153.38 臺灣), 04/01/2021 22:01:37
→
04/01 22:37,
3年前
, 4F
04/01 22:37, 4F
→
04/01 22:37,
3年前
, 5F
04/01 22:37, 5F
warning我沒仔細看明天確認一下, error當然是沒有的 不然就無法執行了
推
04/01 22:56,
3年前
, 6F
04/01 22:56, 6F
→
04/01 22:56,
3年前
, 7F
04/01 22:56, 7F
→
04/01 22:56,
3年前
, 8F
04/01 22:56, 8F
這樣的話 那我想再請教一下關於解構式的意義了
我以為會跑解構式就已經是把這個物件準備從memory中移除了耶
以new的方式來看 用上面相同的程式碼
我如果寫
StructB *pB = new StructB;
delete pB;
在delete pB之後在VC裡面debug看m_nB的數值會是???? 表示無法存取的狀態
請問靜態宣告local變數跟動態new變數 在free跑完解構式的差異是?
※ 編輯: Keitaro (1.163.153.38 臺灣), 04/01/2021 23:32:52
→
04/01 23:57,
3年前
, 9F
04/01 23:57, 9F
我懂了 您的意思是說在stack上的需要等這個stack被洗掉才會真正release是嗎?
→
04/01 23:57,
3年前
, 10F
04/01 23:57, 10F
→
04/01 23:57,
3年前
, 11F
04/01 23:57, 11F
感恩 來去學一下 謝謝
※ 編輯: Keitaro (1.163.153.38 臺灣), 04/02/2021 00:14:47
→
04/02 00:19,
3年前
, 12F
04/02 00:19, 12F
→
04/02 00:21,
3年前
, 13F
04/02 00:21, 13F
我想您的意思應該是說當rsp/rbp改掉的時機是指
local variable解構式跑完->stack回到上一層 這個階段
但這個stack在記憶體的位置並沒有被free掉 只是rsp/rbp改成上一層stack而已
所以我去存取這個local variable還能存取到他的數值
如果我想法是正確的 是否我改成這樣
void foo2() // 不做任何事
{}
int main()
{
StractA stA;
foo(stA);
foo2();
return 0;
}
是否這樣foo()的stack就會被洗掉了? stA.m_pB->m_nB 再也無法存取?
※ 編輯: Keitaro (1.163.153.38 臺灣), 04/02/2021 00:37:31
推
04/02 00:33,
3年前
, 14F
04/02 00:33, 14F
→
04/02 00:33,
3年前
, 15F
04/02 00:33, 15F
我了解 只是我想知道compiler到底是偷做了甚麼事顛覆了我對變數lifecycle的認知這樣
我當然是不敢這樣去用上一個stack的local variable的.
※ 編輯: Keitaro (1.163.153.38 臺灣), 04/02/2021 00:44:06
→
04/02 01:52,
3年前
, 16F
04/02 01:52, 16F
→
04/02 01:53,
3年前
, 17F
04/02 01:53, 17F
是的 我以為lifecycle結束就跑解構式
已經跑過解構式的物件 在記憶體上就已經被刪除
既然被刪除就應該是無法存取了 我一直以為是這樣
→
04/02 02:31,
3年前
, 18F
04/02 02:31, 18F
→
04/02 04:14,
3年前
, 19F
04/02 04:14, 19F
→
04/02 04:14,
3年前
, 20F
04/02 04:14, 20F
→
04/02 04:14,
3年前
, 21F
04/02 04:14, 21F
→
04/02 04:17,
3年前
, 22F
04/02 04:17, 22F
→
04/02 04:17,
3年前
, 23F
04/02 04:17, 23F
原來如此 所以讀到那個1真的只是運氣好而已
推
04/02 08:17,
3年前
, 24F
04/02 08:17, 24F
→
04/02 08:17,
3年前
, 25F
04/02 08:17, 25F
→
04/02 08:17,
3年前
, 26F
04/02 08:17, 26F
推
04/02 13:02,
3年前
, 27F
04/02 13:02, 27F
→
04/02 13:03,
3年前
, 28F
04/02 13:03, 28F
→
04/02 13:04,
3年前
, 29F
04/02 13:04, 29F
了解了 非常感謝以上各位的說明 讓小弟我又學到不少 謝謝!
※ 編輯: Keitaro (1.163.153.38 臺灣), 04/02/2021 13:45:36
推
04/03 03:43,
3年前
, 30F
04/03 03:43, 30F
推
04/06 03:11,
3年前
, 31F
04/06 03:11, 31F
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章