2011-08-28 87 views
3

是否破壞自動對象(在堆棧上創建的對象)保證執行不在之前他們超出範圍?自動對象破壞

澄清:

#include <iostream> 

class A { 
    public: 
    A() { 
     std::cout << "1"; 
    } 
    ~A() { 
     std::cout << "3"; 
    } 
}; 

void test123() { 
    A a; 
    std::cout << "2"; 
} 

要打印"2"a不需要任何更多,所以理論上編譯器可以嘗試優化,並儘快銷燬a因爲它不需要任何更多。

我可以依靠上述功能總是印刷123

+0

我從這個問題中瞭解到你來自垃圾收集的背景。例如,在.NET中,這種行爲是沒有保證的; GC可以隨時在最後一次參考之後完成「a」,在這種情況下,它將是最後一行。但是,在C++中,如下所述,它是嚴格定義的。 –

+0

你猜對了完全錯誤:) ---我只是用它來實現模塊的循環模式。 – bitmask

+0

唉,值得一試:) –

回答

9

堆疊對象的破壞順序被嚴格定義 - 它們在聲明的相反的順序執行,當你離開的範圍(可以通過運行關閉{}的端部,或者通過return,或者由異常)。所以,你會總是123那裏。

但是請注意,編譯器優化是由'as-if'規則來管理的。換句話說,一個編譯器可以提早銷燬一個對象,只要生成的程序在正常情況下的行爲「as-if」被銷燬。在這種情況下,因爲你輸出了,所以編譯器必須在適當的時間安排輸出。但是,如果您有例如delete d指向原語類型的指針,並且編譯器可以證明沒有其他指向該值的指針,則原則上可以先移動該delete。關鍵是沒有合規計劃能夠注意到這種優化。

+0

聽起來不錯。在實際情況中,不僅存在'std :: cout',而且還有很多副作用 - 在銷燬對象之前進行了大量的函數調用和數據結構修改。如果編譯器首先銷燬對象,即使它在函數中的任何地方都沒有使用,所有東西都會中斷。所以,根據你的解釋我是安全的,對吧? – bitmask

+1

@bitmask,是的,編譯器將以一種有效的方式執行析構函數,並在範圍的末尾運行。在析構函數中執行清理的副作用被認爲是很好的風格(通常稱爲RAII風格) – bdonlan

+1

感謝您的確認:) – bitmask

3

該標準確定該代碼的正確行爲是打印「123」。編譯器可以在保持相同語義的同時儘可能多地更改代碼(as-if rule),並且在此對代碼進行重新排序會改變語義,因此不允許符合的編譯器執行此操作。

0

構造函數可能有副作用。例如,他們可能會實現一個互斥鎖,即構造函數鎖和解鎖器會解鎖一個互斥鎖。因此123是必需的。