[英]Destructors in C++ (Compared to java)
到目前為止,我一直在用Java編寫程序。 所以當我開始使用C ++時,首先想到的是如何破壞/刪除/完成我不再需要的對象。
使用Java我曾經將它們設置為null
因此垃圾收集器正在處理它。 但是,我不知道C ++的價值。 我發現這篇文章http://en.wikipedia.org/wiki/Comparison_of_Java_and_C%2B%2B解決了我的大部分問題。 但仍有一些我不明白的事情。
1)在Java中有一種方法可以強制垃圾收集器在現場清理(這並不總是有用,因為它在運行之前等待一些垃圾堆疊)。 有沒有辦法用C ++做到這一點?
2)(C ++)與上面相反,我怎樣才能使對象處於“標記為刪除”的狀態,程序決定何時清理它(如Java)?
3)(C ++)我應該強迫垃圾收集器在現場清理(我很確定這不是正確的方式,但我要求確定)?
如果你能給出一個代碼觸發器的小代碼示例,我會贊美它。
1)如果您的對象處於自動存儲中,您可以限制其范圍:
{
X x;
//...
} //x gets destructed here
如果在動態存儲中,則在完成后刪除它們:
X* x = new X;
//...
delete x; //x gets destructed
2)你不能(至少以干凈的方式)。 您必須指示C ++何時刪除對象,即使該指令包含結束括號。 (請參閱第一個代碼段)
3)C ++中沒有垃圾收集器。 看兩個片段。 您必須顯式刪除對象(如果在動態存儲中),或者如果在自動存儲中,它們將被自動刪除(但不會被垃圾收集器刪除)。
值得研究的是智能指針(那里有大量的實現),但這也不是垃圾收集器。 它只是為您節省了管理內存的麻煩。 但它與Java無異。
C ++在這個領域與Java非常不同,所以這里有一個簡短的概述:
分配:為對象留出內存。
結構:准備使用該物體。
破壞:物體“完成”一切並自行拆解。
deallocation:將內存返回給系統。
int main() {
int myint; //automatic int object is allocated and constructed
//stuff
} // when main ends, automatic int object is destroyed and deallocated
int main() {
int* mypointer; //automatic pointer object is allocated and constructed
mypointer = new int; //dynamic int object is allocated and constructed
//stuff
delete mypointer; //dynamic int object is destroyed and deallocated
} // when main ends, automatic pointer object is destroyed and deallocated
// note: Pointers to _not_ delete the object they point to.
class myclass {
//members
public:
myclass() {} //this is the default constructor
myclass(const myclass& rhs) {} //this is the copy constructor
myclass& operator=(const myclass& rhs) {return *this} //this is the assignment operator
~myclass() {} //this is the destructor
};
當函數結束時,函數本身中的所有變量(我們稱之為自動)都會調用它們的析構函數,然后自動釋放它們。 這意味着對於函數本地的對象,它們會在函數結束的瞬間自動清理。 這也適用於一個類的成員。 當它被銷毀時,它的每個成員都將被自動銷毀。 這意味着大多數析構函數都是空的。
如果手動分配東西(使用new
關鍵字),則必須使用delete
關鍵字手動銷毀和解除分配。 當你調用delete
,它會在那里銷毀(並解除分配)然后,並且在完成之前不會繼續。 如果你忘記了,它就不會得到DEALLOCATED(盡管如此, 某些操作系統會在你的程序結束時解除分配)。
由於人們會犯錯誤,因此在需要動態對象時要做的“正確”事情是:
int main() {
std::unique_ptr<myclass> myptr = new myclass(); //allocate and construct
} //both the unique_ptr and the dynamic object are destroyed and deallocated
而unique_ptr
足夠聰明,可以自動清理它所指向的東西,讓你有更大的顧慮。
C ++這樣做的原因是因為如果你有一個代表該文件的對象F
,它可能對該文件有一個獨占鎖。 在C ++中,一旦F
被銷毀,您可以立即創建使用該文件的對象G
在Java中,有沒有保證的finalizer
將永遠運行,這意味着文件可能會保持鎖定狀態,直到您的程序結束。 (不太可能,但可能)
C ++中沒有垃圾收集器。 你應該自己編寫和運行析構函數。 在C ++中,忘記運行析構函數是一個常見錯誤。
如果你的對象與分配new
,那么你應該刪除它delete
。 所以, new
調用contructor,而delete
調用析構函數。
myclass *p = new myclass();
// do something
delete p;
這稱為動態對象分配。
如果您的對象是“正常”定義的,則當超出范圍時它將自動被破壞。
myclass a;
// do something
// will destructed when }
這稱為自動對象分配。
PS你也沒有在Java中分配空值,因為垃圾收集器是為了不打擾刪除對象而發明的。
C ++中的垃圾收集始終是即時的。 沒有單獨的垃圾收集器; 刪除對象時,它會立即刪除當前線程。 它看起來像這樣:
MyObject* foo = new MyObject();
...
delete foo;
有可用於C ++的垃圾收集框架,您還可以查看智能指針,這也是垃圾收集的一種形式。
注意James的評論如下 - 對象的析構函數和操作符刪除總是立即被調用,但它是否依賴於實現,關於內存是否可以立即可用。
C ++使用RAII(資源獲取是初始化)編程習慣,沒有像Java中的垃圾收集器或Objective-C 2中的AutoZone那樣的自動內存管理。因此,正確的實例清理很容易變得復雜。 回答你的問題:
廣告1:C ++中沒有GC,因此您必須手動刪除對象或使用引用計數技術或更好的智能指針,它們現在是C ++ 11標准的一部分,但據我所知它不可用於任何C ++編譯器。 現在,您可以使用Boost庫中的智能指針模板: http : //www.boost.org/doc/libs/1_48_0/libs/smart_ptr/smart_ptr.htm 。 新的C ++標准直接采用了Boost實現,因此在不久的將來切換到新標准時將沒有問題(MSVC 2012將實現C ++ 11支持)。
廣告2:無法標記,只需在正確位置“手動”刪除它或將此任務留在智能指針上。
廣告3:不適用。
最后,始終有最簡單的選項 - 不要在堆上分配對象,這意味着動態。 在Java中沒有這種可能性,但在C ++中有。 我甚至讀過一些關於C ++編程的Stroustrup(C ++的創建者)的好書,在C ++創建時,不推薦這樣的動態分配。 他說:要讓RAII正常工作,一定不能進行動態分配 - 今天聽起來很奇怪,但這就是Stroustrup所寫的,它不是我的頭腦,我個人動態分配幾乎所有人都做的事......
靜態分配的主要原因是,一旦超出范圍,對象就會被刪除,因此根本不必擔心異常安全和清理。 如果您動態分配實例,則如果實例離開當前范圍,則不會自動刪除它 - 如果您沒有手動刪除實例,則會發生內存泄漏。 考慮一下簡單的try-catch塊:
try
{
Class *instance = new Class;
//some error
}
catch(...)
{
//error caught - current execution is terminated immediately, instance is no deleted - memory leak.
}
我在Java中有一個始終被調用的finally語句,因此您可以在拋出異常時執行必要的清理。 但是在C ++中你遇到麻煩... 除非你使用提到的智能指針或一些非常類似的技術。當使用智能指針時你不必再擔心清理了(在實踐中不完全正確,但你的生活肯定會是更容易,你的代碼更少的bug)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.