2013-08-28 27 views
0

我是C++新手,從目前爲止,當您調用指向堆上創建的某個指針的delete時,學到的指針會被擦除,內存被釋放,對吧?即使刪除對象後,爲什麼我可以訪問成員函數?

然而,當我嘗試這樣做的一個簡單的類:

class MyClass 
{ 
    int _Id; 
public: 
    MyClass(int id) : _Id(id) 
    { 
     std::cout << "$Constructing the damn thing! " << _Id << std::endl; 
    } 
    ~MyClass() 
    { 
     std::cout << "?Destructing the damn thing! " << _Id << std::endl; 
    } 
    void Go_XXX_Your_Self() 
    { 
     std::cout << "%OooooooooO NOOOOOO! " << _Id << std::endl; 
     delete this; 
    } 
    void Identify_Your_Self() 
    { 
     std::cout << "#Object number: " << _Id << " Located at: " << this << std::endl; 
    } 
}; 

這些都只是一些愚蠢的測試,看看如何刪除作品:

int main() 
{ 
    MyClass* MC1 = new MyClass(100); 
    MyClass* MC2 = new MyClass(200); 
    MyClass* MC3 = MC2; 

    std::cout << MC1 << " " << MC2 << " " << MC3 << " " << std::endl; 

    MC1->Identify_Your_Self(); 
    MC2->Identify_Your_Self(); 
    MC3->Identify_Your_Self(); 

    delete MC1; 

    MC1->Identify_Your_Self(); 


    MC3->Go_XXX_Your_Self(); 

    MC3->Identify_Your_Self(); 


    delete MC2; 

    MC2->Identify_Your_Self(); 

    MC2->Go_XXX_Your_Self(); 

    MC2->Identify_Your_Self(); 

    return 0; 
} 

下面是輸出:

$Constructing the damn thing! 100 
$Constructing the damn thing! 200 
0x3e3e90 0x3e3eb0 0x3e3eb0 
#Object number: 100 Located at: 0x3e3e90 
#Object number: 200 Located at: 0x3e3eb0 
#Object number: 200 Located at: 0x3e3eb0 
?Destructing the damn thing! 100 
#Object number: 0 Located at: 0x3e3e90 
%OooooooooO NOOOOOO! 200 
?Destructing the damn thing! 200 
#Object number: 4079248 Located at: 0x3e3eb0 
?Destructing the damn thing! 4079248 
#Object number: 4079280 Located at: 0x3e3eb0 
%OooooooooO NOOOOOO! 4079280 
?Destructing the damn thing! 4079280 
#Object number: 4079280 Located at: 0x3e3eb0 

所以,我的問題是,爲什麼我仍然可以在調用Go_XXX_Your_Self()和Identify_Your_Self()之後調用對象被刪除?

這是如何工作在C + +? (有刪除後有嗎?)

也可以檢查,看看它不存在嗎? (我知道理論上是不可能的,但我很好奇,看看有什麼方法)

+2

你只是在操作系統和贏得比賽......你最終會輸。 – Andy

+0

注意'0x3e3eb0'的對象是如何從'200'變爲'4079280'的。 –

+1

因爲未定義的行爲是一個無情的丫頭。遲早,她會打破你的。 – WhozCraig

回答

8

所以,我的問題是,爲什麼我仍然可以在對象被刪除後調用Go_XXX_Your_Self()和Identify_Your_Self()?

由於undefined behavior

這是如何工作在C + +? (有沒有刪除它之後?)

因爲undefined behavior。不能保證它在其他實現上的工作原理是一樣的。再次,undefined behavior

你也可以檢查,看看它不在嗎? (我知道在理論上是不可能的,但我很好奇,看看方法是在那裏什麼)

delete MC1; 
MC1 = nullptr; 

通過設置指針nullptrdelete荷蘭國際集團後,它的運行時間是最有可能檢測到您的訪問一個無效的,你沒有權利使用的位置。另外,通過對所有適用的指針進行認真的操作,您可以檢查該對象是否有效(如果不是,則爲有效。)nullptr)。

if(my_ptr) { 
    // my_ptr is most possibly valid (though you can still go wrong) 
    // use my_ptr 
} 

同樣,你也應該設置原始指針到nullptr時,他們還沒有初始化爲某個合法地址。

MyClass* some_ptr = nullptr; 
... 

但同樣,如果你有機會獲得現代C++ 11級的設施,這是更好的沒有在所有使用原始指針,並且只使用std::unique_ptrstd::shared_ptr(根據您的需要語義)。在未來的C++標準修訂版本中,您可能還想使用proposed std::exempt_ptr,它是一個非擁有,僅限觀察指針包裝器。

0

你是不吉利的。記憶還沒寫完,事情仍然正常。

其他時間你可能會很幸運,你會很難崩潰,這將突出問題。

訪問內存,你已經delete D是不應該做的。在C++中,不要這樣做,因爲編譯器不會阻止你。

2

當您在一個對象上調用delete時,該對象所使用的內存可供另一個使用new(或者真的,由任何使用堆的東西)使用。在此之前,被刪除的對象可能(或可能不是)保留其先前的值。但最終,隨着程序繼續運行,被刪除的對象所使用的內存將被覆蓋,然後如果幸運的話會發生不好的事情:您的程序將崩潰。如果你不走運,你的程序將不會崩潰,直到它在現場部署。

+0

+1。請注意,您的頭像與非常活躍的C++社區成員在此使用的頭像非常相似。 – Potatoswatter

+0

@Potatoswatter:好吧,我猜巧合發生了......幾年前我創建了這個頭像,並且大多不關心它,但似乎很多論壇都會從gravatar.org自動檢索它。 – zentrunix

0

C++編譯器通常不會生成代碼來代表您檢查指針的有效性。如果你在意,你需要自己提供代碼。由於訪問釋放的內存會調用未定義的行爲,因此這樣做的結果是非確定性的。

不管怎樣,您都不應該操縱原始指針,而是依賴於其中一個智能指針。然後,你很可能會遇到這個錯誤,因爲你會依賴指針超出範圍以允許內存被破壞。

然而,即便如此,你還是可能會遇到在那裏你逼壞事情發生,例如案例:

std::unique_ptr<Foo> p(new Foo); 
    p->foo(); 
    p.reset(0); 
    p->foo(); 

你可以嘗試趕上在運行時這些問題與智能指針包裝,做一些爲你檢查的形式:

template <typename T> 
class CheckedSharedPtr { 
    std::shared_ptr<T> ptr_; 
public: 
    //... 
    T * operator ->() const { 
     if (ptr_ == 0) { 
      //...throw something 
     } 
     return ptr_.operator->(); 
    } 
}; 

但是,這只是增加額外的開銷,每個指針訪問。更好的方法是利用一個很好的靜態代碼分析工具,可以幫助識別代碼中的這些類型的問題以及其他許多問題。

0

機制是刪除只是告訴系統內存不再需要,可以重新使用以再次使用。沒有采取其他行動。這是在安全披露中看到的免費使用後錯誤的基礎。程序員有必要不要再使用內存。

爲此,RAII是一種嘗試減少此問題的方法。

相關問題