[英]C++ - Why can you return a reference to a “stack object”
我不明白這段代碼是如何工作的:
class AAA {
public:
short a, b;
};
AAA &getRef() {
AAA aaa = {2, 6};
return aaa;
} // 'aaa' is destroyed here right?
int main() {
AAA &ref = getRef();
cout << ref.a << ", " << ref.b << endl;
cin.ignore();
return 0;
}
嘗試訪問ref.a
和ref.b
應該不會出錯? 當我使用指針時,我也不會出錯。 我的意思是,這每次都會打印“ 2,6”。
編輯:是因為內存仍然設置為那些數字嗎?
之所以“有效”,是因為函數返回時aaa
的內存尚未被覆蓋。 如果將AAA
類修改為具有用於修改a
和b
的析構函數,或者如果您使用某些寫入堆棧的代碼,則幾乎可以肯定會覆蓋這些值。
C ++標准將返回對局部變量的引用定義為“未定義的行為”。 該標准通常在例如難以確定該值確實基於堆棧的情況下執行此操作。
例如,考慮:
class BBB
{
AAA& x;
public:
BBB(AAA& a) : x(a) {}
AAA& getX() { return x; }
};
AAA& getReg()
{
AAA aaa = { 2, 6}
BBB bbb(aaa);
return bbb.getX();
}
大多數現代編譯器都會針對您所遇到的情況發出警告,有些人可能還會對我剛剛編寫的代碼發出警告。 但是幾乎肯定可以提出一些更復雜的案例,以解決無法診斷“錯誤”的問題。
不幸的是,這是調用未定義行為的非法代碼,但編譯器未將其標記為錯誤(盡管如果啟用更多編譯器診斷,則可能會標記為錯誤)。
它碰巧是偶然發生的,大概是因為創建對象的內存位置沒有再用於其他任何用途,並且沒有被清除或覆蓋,因此您很幸運地將這些值放在那里。
看來您想要“證明”它可能會失敗。 也許嘗試:
int main() {
AAA &ref = getRef();
cout << "Hello, world!" << endl;
cout << ref.a << ", " << ref.b << endl;
}
另外,您應該啟用並注意編譯器的警告。
用具有復雜析構函數(如string
)的用戶定義類型替換short
,您可能會看到此崩潰。 因為內存已被回收,但是舊值仍然位於該內存中,所以即使銷毀后,您(有時)仍可以看到內置類型(如int
, short
等)的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.