回覆列表
  • 1 # 使用者9150357517591

    首先要明確,解構函式是在物件走出生命週期時被呼叫,最常見的情況大概是出現以下程式碼:

    於是這一對{}之間所有具名物件(區域性變數)都會被呼叫解構函式。

    還有可能是另一種程式碼:

    於是這一行中出現的所有臨時物件(即右值)都會被呼叫解構函式。

    當然不能忘了更為明顯的

    接下來是解構函式需要幹什麼。

    第一部分,是寫在~T(){}的大括號裡面的內容,這部分由程式設計師掌控,一般幹以下事情。

    釋放記憶體。delete或者free所有在這個物件生存期間產生的堆記憶體釋放控制代碼。如各種檔案(FILE *)、視窗(HANDLE)等catch所有的異常(呼叫的函式有可能產生異常),不可以讓異常逃離解構函式。

    C++異常被丟擲時,會進行棧回退操作(stack unwinding),即在異常層層向上丟擲時保證對已經被構造的物件執行解構函式,而這是做到上面說的那一堆釋放操作的唯一機會。相對的,執行解構函式時很有可能當前正在進行異常處理,而C++中不可以同時處理兩個異常,所以你需要保證解構函式(和它內部執行的其他函式)不能丟擲異常。

    第二部分,是編譯器隱式生成的內容,在第一部分完成之後執行,不需要自己寫,主要有:

    把虛擬函式表指標變成基類的,也就是此時開始這個物件已經是基類物件了。調整this指標指向基類部分開頭,並呼叫基類的解構函式。虛擬繼承情況下,標記虛基類已經被析構過等等

    如果是多繼承情況下,會對每個基類執行類似的操作,確保所有的基類能成功析構恰好一次。

    第三部分,如果你把解構函式定義為虛擬函式,那麼編譯器會額外新增一個析構代理函式。

    這個函式是為了實現使用基類指標delete物件,所做的事情如下:

    調整this指標。在多繼承情況下,基類指標可能指向物件中間,此時這個函式需要把傳遞進來的this指標調整至物件開頭,否則無法保證分配記憶體時返回的void *和此時的this指標的值一致。(即pthis = static_cast<Derived *>(pBase); )呼叫前面兩部分的解構函式。(或者是執行具有相似功能的語句)用調整好的this指標去釋放記憶體(free)。

    強調:如果打算讓這個類成為基類,必須把解構函式宣告為虛擬函式。

    解構函式為了實現C++的核心思想RAII(資源獲取即初始化)而存在,但是它的目的並不是為了實現什麼邏輯功能,只是為程式設計師提供個機會為自己乾的好事打胎……實際寫程式時建議的操作是讓編譯器為你生成解構函式(如使用智慧指標解決問題)而不是自己寫。

  • 中秋節和大豐收的關聯?
  • 絕地求生什麼槍最好用,為什麼?