2013-02-24 24 views
0

我經歷了與當在程序退出的Visual C++運行時自毀我的對象,而惱人的問題絆倒了。的Visual C++運行時對象破壞秩序

我有被用來確保某些國家引用是有效的一類。我需要將狀態存儲一段未知的時間,在此期間狀態可以被銷燬,我不能使用shared_ptr。所以我用

class MyClass 
{ 
private: 
    static std::list<MyClass*> make_list(); 
    static std::list<MyClass*> refed_list;   
    static void StateClosed(B* state); 

public: 
    B* state; 
    MyClass(B* state); 
    virtual ~MyClass(); 

    bool still_valid() const; 
}; 

MyClass每個實例都增加了自己在其構造refed_list,並在其析構函數刪除自身。如果封裝狀態爲關閉狀態,則MyClass會得到通知,並會檢查refed_list是否爲封裝實例並使其指針失效。這並不重要,重要的是它使用了一個static list,它在構造函數/析構函數中訪問這個列表。我在定義了MyClass的文件中初始化了refed_list

現在,問題..當我的程序關閉時,運行時會在某個時間點清除refed_list,然後清除MyClass的實例,調用它們的析構函數。然後他們嘗試訪問已被清理的refed_list。這導致我的迭代器不正確,並且我得到未定義的行爲,在這種情況下調試斷言失敗。

有沒有解決這個問題的方法嗎?我懷疑我可以指定在不同編譯單元中的哪個訂單對象被銷燬,但是有沒有辦法檢查refed_list是否仍然有效?目前我檢查是否refed_list.size() == 0,它似乎工作,但這種行爲也是不明確的(我認爲?)。

+1

聽起來像一個單身一輩子的問題。我認爲Scott Meyers或Andrei Alexandrescu寫了一些關於以三種不同方式管理他們的內容。鳳凰辛格爾頓可能會成爲你的衚衕。 – 2013-02-24 11:14:02

+0

這是我爲什麼不允許我的團隊使用全局類實例的衆多原因之一。因爲在程序退出期間對象破壞的順序是非確定性的,或者很難正確確定。無論如何,在WinMain/main返回之前,你是否可以運行應用程序清除函數?或者更好的是,除非那些析構函數執行關鍵任務,爲什麼不在應用程序關閉時讓所有對象泄漏呢? – selbie 2013-02-24 11:45:38

+0

@selbie我開始認爲這是一個好主意。我這樣做的原因是因爲我需要存儲一個在使用前可能會失效的對象,並且我不能使用'shared_ptr',所以我需要通知對象它們是否有效。因此,我需要跟蹤對象,這就是爲什麼我有靜態列表。但是,是的,如果我重寫一些東西,我可以手動關閉它,這應該可以解決我的問題。掛鉤進程有時會讓事情變得困難.. – user1520427 2013-02-24 21:47:17

回答

2

您可以隨時在refed_list是在啓動時初始化的指針。這樣它永遠不會被清理。 (和它使用的所有內存都通過你的進程退出操作系統恢復。)

如果這聽起來像一個黑客以解決更深層次的設計問題,那麼它可能是。 :)

+0

是的,設計不是一個好的,我最終不得不做一個模仿析構函數的方法,所以我可以在運行時清理我的全局變量之前清理它。 – user1520427 2013-02-24 21:53:55

0

我不認爲這是正確的:

當我關閉程序運行在某個時候清理refed_list,並在此之後它清理的MyClass實例,調用析構函數。

運行時肯定會清理列表,但不是列表中的對象,因爲它們是指針。唯一的方法是使用像shared_ptr這樣的智能指針類。儘管如此,如果你這樣做了,對象會試圖在列表被銷燬的時候訪問列表,但我不確定它是未定義的行爲,但它肯定看起來不穩定。

也許你應該重新設計它,以便對象不需要引用它們存儲的列表,或者至少做到這一點之前列表被銷燬(並且我的意思是在列表之前:: 〜列表甚至被稱爲)。

+0

我並不是說它釋放了它存儲的指針的內存,我的意思是繼承'MyClass'的對象稍後被銷燬,所以運行MyClass析構函數,嘗試訪問現在被破壞的列表。但是,是的,聽起來像重新設計是爲了.. – user1520427 2013-02-24 21:39:44