2013-10-04 47 views
0

我無法理解此代碼的工作原理。我已經在C#世界上呆了一段時間,並想在C++ 11中深入研究C/C++之前,像RValue Refs和移動語義一樣。可以訪問返回的LValue引用在分配它的對象被銷燬後

我不知道爲什麼這個代碼是我寫的作品:

class InnerMember 
{ 
    private: 
     int _iValue; 

    public: 
     InnerMember(): _iValue(0) {}; 
     InnerMember(int iValue) : _iValue (iValue) {}; 

     int GetValue(void) { return _iValue; } 
     int SetValue(int iValue) { _iValue = iValue; } 
}; 

class TestClass 
{ 
    private: 
     InnerMember _objValue; 

    public: 
     TestClass() : _objValue(1) {}; 

     void SetValue(int iValue) 
     { 
      _objValue.SetValue(iValue); 
     } 

     InnerMember& GetRef(void) 
     { 
      return _objValue; 
     } 

     virtual ~TestClass() { std::cout << "I've been released!" << std::endl; } 
}; 

int main (int argc, char *argv[]) 
{ 

    TestClass* pobjTest = new TestClass(); 

    std::cout << "Before:" << std::endl; 
    std::cout << pobjTest->GetRef().GetValue() << std::endl; 

    pobjTest->SetValue(5); 

    InnerMember& robjInner = pobjTest->GetRef(); 

    delete pobjTest; 

    std::cout << "After:" << std::endl; 
    std::cout << robjInner.GetValue(); 

    return 0; 
} 

輸出是:

Before: 
1 
I've been released! 
After: 
5 
Press any key to continue... 

我認爲這將導致一個錯誤,因爲我訪問引用對象InnerMember TestClass被銷燬後,從TestClass開始。是否有某種返回值優化正在進行?或者它真的返回一個副本而不是傳回參考?

我用GCC沒有優化(-O0),它仍然運行沒有問題。

我也使用-S開關來生成程序集,但是我的AMD64知識是生鏽的,名稱不起作用。

回答

0

robjInner仍然是對內存中某些已刪除對象的引用。 這會導致未定義的行爲。

刪除後,引用robjInner已被留下懸掛。你回來以前的價值,因爲沒有人聲稱這段內存呢。

here

複製的先前有效的引用僅變爲無效在兩種情況:

  1. 如果它是指被自動分配一個對象,其超出範圍,

  2. 如果它引用已釋放的動態內存塊內的對象。

首先是容易的,如果所述參考具有靜態作用域來自動檢測,但仍是一個問題,如果該參考是動態分配對象的成員;第二個更難以保證。這些是參考文獻中唯一關心的問題,並通過合理的分配政策適當解決。

1

這是未定義的行爲,這意味着即使是「正確的」行爲也可能發生。當你用C++刪除某些東西時,它不會從內存中刪除,因此在其他東西寫入之前訪問它有時可能仍然有效。

0

您可以在InnerMember析構函數中添加打印語句以查看發生了什麼。在TestClass之後你會看到InnerMember被銷燬,你得到的5是因爲沒有人寫入那部分內存。但是那個參考不再有效。

+0

你是對的,它確實在添加到InnerMember的析構函數中。我不知道爲什麼我認爲某些DEP在發佈後會訪問堆內存。正如對方提到的那樣,未定義的行爲。謝謝大家! – ninlar

相關問題