析構函數是被執行的一類的特殊成員函數時,它的類的對象超出範圍或每當刪除表達式應用於一個指針,指向類的對象。
析構函數的名稱與前綴爲波形碼~
的類名稱完全相同,它既不能返回值也不能使用任何參數。析構函數可以爲走出程序如關閉文件之前釋放資源,釋放內存等
調用析構函數是非常有用的,每當一個對象的生命週期結束,其中包括
- 程序終止,爲使用對象靜態存儲持續時間
- 螺紋出口處,用於與線程本地存儲持續時間的對象(因爲 C++ 11)的範圍
- 端,用於與自動存儲持續時間的對象和用於 臨時變量,其壽命通過結合到擴展
- 刪除表達式,對於具有動態存儲持續時間的對象,對於無名臨時對象,完整表達式的結尾爲 ;
- 堆棧展開,對於具有自動存儲持續時間的對象,當一個 異常轉義它們的塊時,未捕獲。
析構函數也可以被直接調用,例如銷燬使用placement-new或通過分配器成員函數(如std::allocator::destroy()
)構造的對象來銷燬通過分配器構造的對象。 請注意,直接調用析構函數直接訪問普通對象(如局部變量)時,會在範圍末尾再次調用析構函數時調用未定義的行爲。
在通用上下文中,析構函數調用語法可以與非類類型的對象一起使用;這被稱爲僞析構函數調用:請參閱成員訪問運算符。
隱式聲明的析構函數:
如果提供了一類式(struct
,class
,或union
)沒有用戶定義的析構函數,編譯器將總是聲明析構函數作爲一個inline
public
構件其類。
刪除隱式聲明的析構函數:
class T
爲隱含的聲明的或默認的析構函數是未定義的(直至C++ 11)定義爲刪除(由於C++ 11),如果下列任何一項是真:
- T已
- T具有不能被破壞直接或虛基類不能被破壞的非靜態數據成員(已經刪除 或不可訪問的析構函數)(已 刪除或無法訪問的析構函數)
- T是一個聯合,並具有非平凡析構函數的變體成員。 (因爲C++ 11)
的隱式地聲明的析構函數virtual
(因爲基類有虛析構函數)和用於釋放函數的查找(操作員刪除()的調用結果模棱兩可,刪除或無法訪問的功能 平凡的析構函數
爲class T
析構函數是平凡的,如果所有以下爲真:。
- 析構函數沒有用戶提供的(意思是,它是 隱式定義的或默認的)
- 的析構函數不是虛擬(即,基類的析構函數是 不是虛擬的)
- 所有直接基類具有微不足道的析構函數
- 類型的所有非靜態數據成員(或類類型的數組) 有微不足道的破壞者
瑣碎的析構函數是不執行任何操作的析構函數。帶有瑣碎析構函數的對象不需要delete-expression,並且可以通過簡單地釋放其存儲來處理。所有與C語言(POD類型)兼容的數據類型都是可破壞的。
隱式定義的析構函數:
如果隱式地聲明的析構函數不會被刪除或微不足道的,它被定義(即,產生和編譯的函數體)由編譯器。這個隱式定義的析構函數有一個空體。
與任何隱式定義的特殊成員函數一樣,隱式定義的析構函數的異常規範是非拋出的,除非它直接調用具有不同異常規範的函數(例如,當它必須調用用戶定義的析構函數具有不同異常規範的成員或基礎子對象)。
破壞序列:
對於兩個用戶定義或隱式定義的析構函數,在執行析構函數的主體之後,編譯器調用的類的所有非靜態非變體成員的析構函數按照聲明的相反順序,然後它以相反的構造順序調用所有直接基類的析構函數(反過來調用它們的成員及其基類的析構函數等),然後,如果這個對象是最重要的,它會調用所有虛擬基類的析構函數。
即使直接調用析構函數(例如obj.~Foo();
),~Foo()
中的return語句也不會立即將控制權返回給調用者:它首先調用所有成員和基類析構函數。
虛擬析構函數:
通過指針底座刪除對象調用未定義的行爲,除非在基類析構函數是虛擬:
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {};
Base* b = new Derived;
delete b; // safe
一個常見的指導方針是,對於鹼的析構函數類必須是公共和虛擬的,或者是保護的和非虛擬的 純虛擬析構函數 析構函數可能被聲明爲純虛函數,例如在基類中需要抽象化,但沒有其他合適的f可能被宣佈爲純虛擬的聯合體。這樣的析構函數必須有一個定義,因爲在派生類中被摧毀了所有的基類的析構函數總是叫:
class AbstractBase {
public:
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() {}
class Derived : public AbstractBase {};
// AbstractBase obj; // compiler error
Derived obj; // OK
例外:
至於其它功能,析構函數可以通過拋出一個異常終止(這通常要求它被明確聲明爲noexcept(false))(因爲C++ 11),但是如果這個析構函數碰巧在堆棧展開期間被調用,則會調用std :: terminate。 雖然std :: uncaught_exception有時可能用於檢測進程中的堆棧展開,但通常認爲不允許任何析構函數通過拋出異常來終止。使用這個功能的一個例子是圖書館SOCI,它依賴於某些無名臨時對象的析構函數拋出異常的能力。
示例: 運行此代碼。
#include <iostream>
struct A
{
int i;
A (int i) : i (i) {}
~A()
{
std::cout << "~a" << i << std::endl;
}
};
int main()
{
A a1(1);
A* p;
{ // nested scope
A a2(2);
p = new A(3);
} // a2 out of scope
delete p; // calls the destructor of a3
}
輸出:從http://en.cppreference.com/w/cpp/language/destructor
我認爲這可以幫助http://en.cppreference.com/w/cpp/language/destructor,以及許多其他文章關於析構函數。 – vahancho 2015-02-11 07:33:33
是的析構函數,它是已經在這裏描述: [析] [1] [1]:http://stackoverflow.com/questions/1395506/in-c-what-does -a波浪線之前,一個函數名,表示 – Lui 2015-02-11 07:59:43