析構函式是c++中乙個神奇的部分,在呼叫析構函式時,並不需要像普通函式一樣寫出函式呼叫的**,而是由編譯器將析構函式插入到程式中合適的呼叫地方。如果你不清楚這些插入析構函式的地方,就會出現一些很難解決的錯誤。
在分析析構函式的執行時,乙個經典的示例是全域性變數的析構過程。我們來考慮下面的**:
當執行這個程式時,將會在呼叫g_punknow的析構函式時發生崩潰。其中的原因是:全域性變數的析構函式是主程式退出時才呼叫的,而在主程式退出時,com環境也將被解除安裝。com的解除安裝工作包括釋放在初始化com環境時所載入的動態鏈結庫。然後當你釋放全域性變數指標時,程式將崩潰,因為程式試圖與乙個不存在的dll通訊。 這個問題並不僅限於全域性變數,有時候區域性變數也會出現這樣的情況:
這段程式非常簡單,在**中有乙個錯誤。智慧型指標的析構函式在什麼時候被呼叫?答案是:當智慧型指標超出作用域的時候被呼叫。由於已經解除安裝了com環境,當你再試圖訪問乙個指向com物件的指標時,將發生與前面一樣的錯誤。 要修正這個問題,就必須在couninitialize之前釋放左右的com指標。方法就是加入乙個看上去似乎沒有必要的作用域:
不過你要確保在**中留下相應的注釋,確保不會被閱讀這段**的人刪除這兩個"多餘的"大括號。 有些人可能會認為這個解決方案很不直觀。那麼下面將給出另外乙個解決方案:將couninitialize放在某個物件的析構函式中。
現在即使你將智慧型指標放在同樣的作用域中依然可行。只要保證智慧型指標是位於ccoinitialize物件之後:
這段**是沒有問題的,因為自動儲存型別物件在呼叫析構函式時的順序與宣告這些物件的順序是相反的。所以物件p首先被析構,然後才是物件init. 到目前為止,我們已經看到了一些在錯誤時刻呼叫的析構函式。現在,再來看一些不會被呼叫的析構函式。 假設有乙個objectlock類,在這個類的建構函式中將獲得乙個鎖,並在其析構函式中釋放這個鎖:
在這段**中,第一部分的操作是在沒有加鎖的情況下完成的,而第二部分操作則是在加鎖的情況下完成的。當函式返回時,這個鎖將自動被釋放。然而如果在這個函式中增加了下面這樣一行**:
這段**的意思是:如果物件被取消了,就提前退出執行緒。但是objectlock物件的析構函式在什麼時候被呼叫呢? 這個析構函式將在return語句中執行,因為此時objectlock物件已經超出作用域。然而,在呼叫exitthread函式之前,析構函式是不會被呼叫的。結果就是,程式使乙個物件被永久鎖定。 有些人可能會爭論:呼叫exitthread是不好的變成習慣,我們應該通過執行到執行緒函式的最後來結束乙個執行緒。然而,有一種情況你必須通過退出函式來退出執行緒:如果是乙個工作執行緒,雖然這個執行緒的生命週期並沒有被程序顯示管理,但執行緒的**是在乙個dll中。這種情況下,標準的做法是:當工作執行緒啟動的時候,呼叫loadlibrary(load count)函式來增加dll的載入計數,而當工作執行緒結束時,呼叫freelibraryandexitthread函式(當然,你也可以同樣使用 getmodulehandleex函式來增加載入計數)。如果使用這種方法,執行緒看起來就像這樣:
其中g_hinst是乙個全域性變數,在這個變數中儲存的是dll的例項控制代碼。在這種情況下,你會遇到和前面同樣的問題:objectlock的析構函式是在函式的括號結束處執行的,但是freelibraryandexitthread函式退出執行緒並且不會再回到函式中。因此,析構函式永遠不會被執行。同樣,我們依然可以使用乙個巢狀的作用域來強制析構函式的執行:
函式模板深入研究
1.編譯器並不是把函式模板處理成能夠處理任意類的函式 2.編譯器從函式模板通過具體型別產生不同的函式 3.編譯器會對函式模板進行兩次編譯 4.在宣告的地方對模板 本身進行編譯 在呼叫的地方對引數替換後的 進行編譯。include using namespace std templatet max t...
變數與函式深入研究
2.區域性變數 2.3.1.static區域性變數的好處 3.函式 在函式外定義的變數稱為全域性變數,也稱外部變數,全域性變數的作用域較廣,全域性變數不屬於任何乙個函式,理論上可被其作用域中的所有函式訪問,因此,提供了乙個不同函式間聯絡的途徑,使函式間的資料聯絡不只侷限於引數傳遞和return語句。...
flex Bindable深入研究
bindable 元資料標籤,它在 中的作用就是向編譯器提供如何編譯程式的資訊。它的最大作用是使程式元件間的資料同步變得容易。在開發中通常用上bindable作用在檢視控制項上,如給它繫結乙個物件,則以後只需要在邏輯層更改這個物件的值,則檢視層的控制項資料會自動更新 同步 而不再需要手動去更新檢視。...