2014-02-18 33 views
1
#include <list> 
#include <iostream> 

struct Foo 
{ 
    Foo(int a):m_a(a) 
    {} 
    ~Foo() 
    { 
     std::cout << "Foo destructor" << std::endl; 
    } 
    int m_a; 
}; 

int main() 
{ 
    std::list<Foo> a; 
    Foo b(10); 
    std::cout << &b << std::endl; 
    a.push_back(b); 
    Foo* c = &(*a.begin()); 
    std::cout << c << std::endl; 
    a.erase(a.begin()); 
    std::cout << a.size() << std::endl; 
    c->m_a = 20; 
    std::cout << c->m_a << std::endl; 
    std::cout << b.m_a << std::endl; 
} 

結果是:爲什麼我可以在列表中刪除一個列表中的對象的成員變量?

0x7fff9920ee70 
0x1036020 
Foo destructor 
0 
20 
10 
Foo destructor 

我通常認爲i之後擦除在一個列表中我不能訪問塔爾對象的成員變量的任何更多的對象。但是在上面我仍然可以訪問c->m_a之後,我已經擦除了c指向的對象,爲什麼?

+7

搜索並閱讀* undefined behavior *。 –

+0

我會想象這是因爲指針仍指向內存,並且知道對象的結構,而真正的析構函數只是允許內存被覆蓋,但這還沒有發生呢 – wrossmck

+0

閱讀[本答案](http ://stackoverflow.com/a/6445794/1782465)。 – Angew

回答

2

Foo* c = &(*a.begin());您創建了一個指向您故意銷燬的對象的指針(通過erase())。然而,對象的內存仍然存在(因爲這是一個非常簡單的應用程序,操作系統並沒有聲稱它是用於其他的)。

所以你有效地使用不再是你的內存來使用。

+0

@JoachimPileborg是的,謝謝你的糾正.... (需要一杯咖啡:)) – fritzone

0

那麼,只要你已經分配了那部分內存(無論是在堆棧上還是在堆上使用new/malloc),數據完整性才能得到保證。

一旦你釋放了數據,你的數據會發生什麼,是未定義的(意味着它取決於實現)。釋放內存的最有效方法是簡單地將內存標記爲可用,將數據留在那裏,直到另一個程序使用malloc聲稱內存的一部分並覆蓋它。這是大多數實現將如何處理這個問題。

C++不檢查您正在閱讀或寫入的數據是否屬於您的程序。這就是爲什麼當程序嘗試將數據寫入無法訪問的內存中的某個位置時,會出現分段錯誤。

在您的情況下,您將釋放內存,然後立即檢查其值。 C++會很高興地執行你的代碼。由於您最近纔將其釋放,所以您的數據仍然存在的可能性非常高(但肯定不能保證:遲早會被覆蓋)。

0

歡迎來到狂野的指針世界。你在這裏得到的是Dangling Pointer(閱讀wiki文章,詳細解釋它)。

這裏基本上發生的事情是,從列表中刪除的項目後,指針c成爲懸擺指針(它是指向它不再被Foo對象佔用的內存位置)。但是C++仍然允許你通過這個指針讀/寫,但副作用將是完全不確定的(意味着任何事情都可能發生)。由於代碼在測試代碼時很簡單,所以你很幸運(或者不幸,因爲這些類型的問題在變老時會變得非常困難和危險)。

+0

幾乎不可能在更大的項目中找到應用程序崩潰的來源 – Zaiborg

相關問題