2009-08-27 84 views
7

我知道在一個dll中創建的內存分配隨後在另一個dll中釋放會導致各種問題,特別是在CRT方面。當涉及到導出STL容器時,這些問題尤其成問題。我們已經經歷了這些各種各樣的問題之前(編寫與我們的庫鏈接自定義Adobe插件時),我們已經定義了自己的分配器,我們在我們所有的容器使用,例如,工作就是圍繞着這些問題:跨dll邊界的內存分配和釋放

typedef std::vector < SessionFields, 
     OurAllocator <SessionFields> > 
     VectorSessionFields; 

typedef std::set < SessionFields, 
     std::less <SessionFields>, 
     OurAllocator <SessionFields> > 
     SetSessionFields; 

將代碼傳入/傳出時,這種方法運行良好,但是我們遇到了一個問題,那就是我們現在不得不調用Adobe SDK中的一個函數,它返回一個填充矢量,當它超出範圍時會導致崩潰。

顯然,在我的代碼中最終釋放了內存時,它在Adobe的SDK中分配的內存屬於不同的堆。所以我在想,也許我可以做一些聰明的事情,比如重寫或導出SDK中使用的分配器,這樣我就可以使用它來清理從其函數返回的容器。

我也在看寫封裝或某種形式的thunking層,因此STL容器將安全地編碼在我的代碼和SDK之間(雖然聽起來很雜亂)。

或者,我也在尋找使用GetProcessHeaps來確定SDK中使用的堆,並嘗試釋放堆而不是默認堆。

有沒有人有任何關於如何解決這個問題的建議?

回答

0

您可能試着查看是否有任何正式的C++規則,當在一個DLL中引發異常並在另一個DLL中引發異常,然後超出範圍時會發生什麼 - 看起來非常相似。對於例外情況,我想認爲您需要提供具有特殊簽名的複製構造函數,儘管我現在不確定它到底是什麼。

6

具有諷刺意味的是,Adobe Source Libraries有一個adobe::capture_allocator類,專門爲此類DLL安全性而編寫。它的工作方式是捕獲當地的newdelete,此時它被實例化,並在對象的整個生命週期內攜帶它們。 (有關詳細信息,請參見adobe::new_delete_t,尤其是實施here。)使用捕獲的delete例程取消分配,保證無論您在哪裏刪除正確的delete

你可以看到整個version_1類型在Adobe源代碼庫,如adobe::any_regular_tadobe::copy_on_write使用capture_allocatorcapture_allocator也應與所有STL容器類型兼容。

更新:capture_allocator不符合標準,因爲它保留了狀態。這不應該成爲它可用性的一大障礙,但它確實意味着它的使用並不能保證與標準兼容容器兼容。

+0

這是一種非常常見的技術,我也在C中看到它,其中一個庫需要其用戶通過某種庫init()點提供分配/解除分配回調。 – Justin 2009-08-27 23:29:14

2

目前我們正在研究一個通過C接口公開C++功能的dll(爲了C#能夠使用上述dll)。

例如:該DLL具有結構myStruct_s接口公開以下功能:

interface.h

#ifndef INTERFACE_TYPES_H 
# error Please include interace_types.h 
#endif 
    myStruct_s * CreateTheStruct() { return new myStruct_s(); } 
    void DestroyTheStruct(myStruct_s * the_struct) { delete the_struct; } 
    void DoSomethingToTheStruct(myStruct_s * the_struct); 

interface_types.h

#define INTERFACE_TYPES_H 
struct myStruct_s; // fwd declaration 
#endif 

接口.cpp

#if defined(__CPPPLUS) || defined(__cplusplus) || defined (__CPLUSPLUS) 
#include<TheRealFileContainingTheRealMyStruct_s.h> 
// handle the .h's functions here 
#endif 

comeOutsideCppFile.cpp

#include "interface_types.h" 
#include "interface.h" 

void main() 
{ 
    myStuct_s * x = CreateTheStruct; 
    DoSomethingToTheStruct(x); 
    DestroyTheStruct(x); 
} 

以上是我們的東西是如何工作的,基本上是一個大概的輪廓: 無論DLL公開需要被:創建,辦理DLL-銷燬側

此代碼是不是100%精確!!!

另外,請記住,如果您使用的是純C++的dll,您可能需要使用相同的設置用於構建該DLL的一個相同的編譯器。

+1

@Maciek:interface.h應該包含非內聯函數。通過使內聯函數,他們將在comeOutsideCppFile.cpp的編制單位,遺址的概念進行編譯。 – shojtsy 2009-11-28 06:33:13