我有一個很好的庫來管理需要返回特定的字符串列表的文件。由於我將要使用的唯一代碼將是C++(和Java,但通過JNI使用C++),我決定使用標準庫中的向量。庫函數看起來有點像這樣(其中FILE_MANAGER_EXPORT爲平臺定義的出口要求):通過dll邊界傳遞引用STL向量
extern "C" FILE_MANAGER_EXPORT void get_all_files(vector<string> &files)
{
files.clear();
for (vector<file_struct>::iterator i = file_structs.begin(); i != file_structs.end(); ++i)
{
files.push_back(i->full_path);
}
}
我用向量作爲參考,而不是返回值的原因是試圖保持內存分配清醒,因爲windows真的很不高興,我用extern「C」圍繞C++返回類型(誰知道爲什麼,我的理解是所有extern「C」都會阻止編譯器中的名稱混亂)。無論如何,使用這種與其他C++代碼通常如下:
#if defined _WIN32
#include <Windows.h>
#define GET_METHOD GetProcAddress
#define OPEN_LIBRARY(X) LoadLibrary((LPCSTR)X)
#define LIBRARY_POINTER_TYPE HMODULE
#define CLOSE_LIBRARY FreeLibrary
#else
#include <dlfcn.h>
#define GET_METHOD dlsym
#define OPEN_LIBRARY(X) dlopen(X, RTLD_NOW)
#define LIBRARY_POINTER_TYPE void*
#define CLOSE_LIBRARY dlclose
#endif
typedef void (*GetAllFilesType)(vector<string> &files);
int main(int argc, char **argv)
{
LIBRARY_POINTER_TYPE manager = LOAD_LIBRARY("library.dll"); //Just an example, actual name is platform-defined too
GetAllFilesType get_all_files_pointer = (GetAllFilesType) GET_METHOD(manager, "get_all_files");
vector<string> files;
(*get_all_files_pointer)(files);
// ... Do something with files ...
return 0;
}
庫被使用add_library(file_manager SHARED file_manager.cpp)通過cmake的編譯。該程序使用add_executable(file_manager_command_wrapper command_wrapper.cpp)在單獨的cmake項目中編譯。沒有爲這兩個命令指定編譯標誌。
現在該程序在mac和linux中都能很好地工作。問題在於windows。在運行時,我得到這個錯誤:
Debug Assertion Failed!
...
Expression: _pFirstBlock == _pHead
這一點,我已經找到了,善良的理解,是因爲可執行文件和加載的DLL之間單獨的內存堆。我相信這發生在內存分配在一個堆中並在另一個堆中釋放時。問題是,對於我的生活,我無法弄清楚發生了什麼問題。內存在可執行文件中分配並作爲對dll函數的引用傳遞,通過引用添加值,然後處理這些內存並最終釋放回可執行文件中。
我會透露更多的代碼,如果我可以但在我的公司的知識產權狀態我不能,所以上述代碼僅僅是例子。
任何人都對這個問題有了更多的瞭解,能夠幫助我理解這個錯誤,並指出我正確的方向來調試和修復它?很遺憾,我無法使用Windows機器進行調試,因爲我在linux上開發,然後對gerrit服務器提交任何更改,從而通過jenkins觸發生成和測試。編譯和測試後,我可以訪問輸出控制檯。
我確實考慮過使用非stl類型,將C++中的向量複製到char **中,但內存分配是一場噩夢,我努力讓它在Linux上很好地工作,更不用說窗口了,它是多個可怕的堆。
編輯:只要文件矢量超出範圍它肯定崩潰。我目前的想法是,放入向量的字符串被分配在dll堆上並在可執行堆上釋放。如果是這樣,任何人都可以啓發我一個更好的解決方案?
1.路過值是好的,C++ 0x中和了具有移動semantix那將使所有的內存複製「理智」。 2.這是一個猜測,但你可能只是遇到「地獄」。解決它的最好方法是導出STL類,請參見[http://stackoverflow.com/questions/767579/exporting-classes-containing-std-objects-vector-map-etc-from-a-dll] – IdeaHat
@MadScienceDreams我剛開始這樣做,但得到了同樣的錯誤。這促使我轉向通過引用傳遞,試圖在可執行文件中保留所有內存分配/釋放。 – SmallDeadGuy