2017-02-14 65 views
0
/* 

清理堆分配的資源這是我的理解是,它加載一個或多個動態鏈接庫(DLL)到其地址空間Windows進程將與所有加載的共享地址空間DLL--意味着這些DLL可以讀取和寫入進程地址空間中的任何內存。但是,如果在堆上分配對象,則每個模塊(無論是.exe還是某個進程的加載的DLL)都從它自己的堆中分配。由於這個原因,對於執行分配的同一個堆釋放內存非常關鍵。問題跨越一個Windows DLL模塊邊界

這一切都對我有意義,我認爲我可以使用std::unique_ptr來幫助保持組織。這是我使用的方法。 (我沒有我的編譯器方便的時刻,但我覺得這些片段/僞代碼將足夠清楚傳達了我的意圖:

*/ 

Library.h

class ILibrary 
{ 
    public: 
    virtual void DoStuff() = 0; 
}; 

struct Deleter 
{ 
    void operator()(ILibrary *p) 
    { 
    delete p; 
    } 
}; 

typedef std::unique_ptr<ILibrary, Deleter> Ptr; 

//*MyLibrary.dll* 
//Includes Library.h 
//Exports: 

void GetMyLibrary(Ptr & library) 
{ 
    library = Ptr(new MyLibrary); // point (1) 
} 

//**Program.exe** 
//Includes Library.h 
//Imports MyLibrary.dll (GetMyLibrary export) 

int main() 
{ 
    Ptr local; 
    MyLibrary->GetMyLibrary(local); 
    local->DoStuff(); 
} // heap corruption on cleanup 

你可以看到我的庫和主程序都使用了相同的頭文件Library.h,我創建了變量local來保存指向我的庫的指針GetMyLibrary方法(在DLL中調用)分配並指定new unique_ptr給我傳入的引用。我在「第一點」使用了賦值,因爲我想從cont繼續使用Deleter用於清理的DLL的分機,而不是最初分配給我的主程序中的local變量的Deleter。意思是,當本地超出範圍時,我希望它的清理能夠觸發DLL的Deleter,而不是最初分配給它的那個Deleter(即我使用library = Ptr(new MyLibrary)而不是library.reset(new MyLibrary),因爲我希望從DLL的上下文中調用Deleter )

無論如何,該程序似乎工作,除了在清理過程中,當本地unique_ptr破壞,我得到一個堆腐敗異常(在調試中),導致我相信我刪除了錯誤的堆(即。 unique_ptr不符合我的預期)

最終,我最終以另一種方式解決了問題,看起來更清潔,但我只是很好奇爲什麼上面的方法失敗了?

+1

「**堆」 - 這是你的問題的很大一部分。就Windows而言,**堆由['GetProcessHeap'](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366569(v = vs.85) .aspx),並且EXE和DLL之間共享堆_is_(因此名稱爲「進程堆」)。 – MSalters

+0

感謝您的鏈接,我會閱讀。 – charunnera

回答

1

您的刪除器是unique_ptr的一部分,並且在指針超出作用域時從main調用。

您應該提供DLL GetMyLibrary()/FreeMyLibrary()和處理內存分配/釋放有(使用應用側RAII),或者通過分配器以GetMyLibrary(),使內存分配和釋放應用程序的責任。

+0

感謝您的回答......我仍然有點困惑。我明白了你對使用獲取/自由導出的看法......多數民衆贊成我以前通常這樣做,但我不太明白爲什麼我的方法正在崩潰。當我調用GetMyLibrary導出時,DLL中的代碼會執行以實例化unique_ptr並新建庫的一個實例。該unique_ptr具有自定義的Deleter(駐留在DLL代碼中)以釋放相應的對象。因此,當我將unique_ptr(通過ref)從DLL複製到main中的unique_ptr時,我期待調用DLL中的Deleter – charunnera

+0

(與您提到的調用FreeMyLibrary()函數類似)我錯過了什麼? – charunnera

+1

這裏輸入'Deleter'是'Ptr'類型的一部分。 'unique_ptr',我相信,在構造或第一次調用'get_deleter()'時,實例化這個對象(類型爲'Deleter'),這兩者都發生在'main()'中。您可以將普通函數作爲deleter傳遞,但在dll/app邊界上使用'unique_ptr'不是最好的辦法。想象一下,如果dll是用不同的編譯器或標準庫或甚至其不同版本編譯的。 – w1ck3dg0ph3r