簡體   English   中英

C ++-為什么您要返回對“堆棧對象”的引用

[英]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.aref.b應該不會出錯? 當我使用指針時,我也不會出錯。 我的意思是,這每次都會打印“ 2,6”。

編輯:是因為內存仍然設置為那些數字嗎?

之所以“有效”,是因為函數返回時aaa的內存尚未被覆蓋。 如果將AAA類修改為具有用於修改ab的析構函數,或者如果您使用某些寫入堆棧的代碼,則幾乎可以肯定會覆蓋這些值。

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 ,您可能會看到此崩潰。 因為內存已被回收,但是舊值仍然位於該內存中,所以即使銷毀后,您(有時)仍可以看到內置類型(如intshort等)的值。

[樣本代碼]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM