2011-11-30 61 views
0

在此先感謝。我現在正在爲C++中的大系統開發一個插件。在我的插件中,我有一些靜態變量。我發現,當它在Linux上以調試模式編譯時,它可以正常工作,沒有任何問題。當它以RELEASE模式編譯時,即某些優化是由編譯器完成的,那麼當我卸載插件時,靜態變量不會被刪除(靜態變量類的析構函數永遠不會被調用),所以內存永遠不會被釋放,下次我重新加載插件時,會導致主程序崩潰!在C++插件中卸載靜態實例變量?

任何人都可以解釋我爲什麼當插件卸載靜態變量不被破壞?注意:靜態變量是一個靜態實例,而不是一個指針!

class MySettings 
{ 
    public: 
     static MySettings& Instance() { 
     static MySettings theSingleton; 
     return theSingleton; 
     } 

     virtual ~MySettings(); 
} 
在插件某處

,它被稱爲像這樣

.... 
MySettings &s = MySettings::Instance(); 
s.xxx(); 
.... 

當我編譯和調試模式跑,我印刷從析構函數的一些信息,它看起來像的實例當插件未被鎖定時,適當破壞。但是,當我編譯和釋放模式運行,析構函數沒有被調用時,該插件unpluged。 我不是插件管理器開發人員,不能講太多。非常感謝你的幫助!

這裏是一段代碼,其加載插件庫。

newLib._libHandle = ::dlopen(path_to_the_plugin_lib, RTLD_LAZY | RTLD_GLOBAL); 
if(! newLib._libHandle) { 
    cerr << "dlopen failed for: " << path << " - " 
      << ::dlerror(); 
    return ""; 

我終於得到它的工作。但仍然不明白爲什麼。這是我做的:

class MySettings 
{ 
    public: 
     static MySettings& Instance() { 
     return theSingleton; 
     } 

    private: 
     static MySettings theSingleton; 
     virtual ~MySettings(); 
} 

MySettings MySettins:theSingleton; 

Sinece的應用程序是非常大的數百萬行代碼。我的疑問是,當gcc在RELEASE模式下編譯時,優化出現問題。

+0

class MySettings public: static MySettings&Instance(){ static MySettings theSingleton; return theSingleton; } virtual〜MySettings(); – user1073719

+0

編輯問題並在其中添加此信息! – karlphillip

+1

這取決於如何加載插件。什麼插件? –

回答

1

我從來沒有嘗試過這個自己,the documentation似乎指定靜態變量應該是「重新初始化」後重裝。對我而言,這與C++的預處理器之間的交互作用並不明顯。你可以嘗試理解(檢查你的供應商的文檔,或者打開二進制文件並查看),但重新設計可能更簡單。一些想法:

如果可以,讓你擺脫單身。正如評論中提到的那樣,目前業界的共識是,在大多數情況下,單身模式比它的價值更麻煩 - 正如你發現的那樣!公平地說,你不會在Java或Ruby中遇到這個問題,但仍然如此。

如果您正在使用gcc進行編譯,您可能會註冊一些鉤子,用於「返回dlopen()之前」和「調用dlclose()之後」。再次從文檔:

...libraries should export routines using the __attribute__((constructor)) and __attribute__((destructor)) function attributes. See the gcc info pages for information on these. Constructor routines are executed before dlopen() returns, and destructor routines are executed before dlclose() returns." 

我很確定這是gcc特定的;如果你不使用gcc,你的平臺可能會提供類似的東西。

如果你不能做到這一點,嘗試切換到單執行的「初始化在第一次使用」的風格。想法是在Instance()中檢測您的MySettings單身是否已經創建好,如果尚未創建,則先創建它。喜歡的東西:

static MySettings* theSingleton = NULL; 
if(theSingleton == NULL) 
    theSingleton = new MySettings(); 
return *theSingleton; 

注意,此版本的Instance()線程安全的;如果你想要的話,你將不得不遇到一些麻煩。另外:theSingleton永遠不會被刪除,所以你的問題會泄漏一些內存/文件描述符/無論什麼時候你的插件重新加載。取決於您在MySettings中保留什麼類型的內容,以及您希望用戶在進程重新啓動之間重新加載插件的頻率,這可能會也可能不會被接受。

希望這會有所幫助。

+0

感謝您的答案我嘗試了創建單例的方法,但遇到了另一個問題,MySettings的構造函數不初始化所需的所有東西,某種延遲初始化。在我的用例中,我需要設置一些初始值,所以在新的MySettings()之後立即調用該方法來初始化一些私有成員,這涉及到爲他們分配內存。那麼我得到了像內存溢出一樣的東西,它立即崩潰了應用程序。 – user1073719