我有一个很好的文件管理库,需要返回特定的字符串列表。由于我将与之使用的唯一代码将是C++(以及通过JNI使用C ++的Java),因此我决定使用标准库中的向量。库函数看起来有点像这样(其中FILE_MANAGER_EXPORT是平台定义的导出要求):
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对我在C++返回类型周围使用extern "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;
}
使用cmake通过add_library(file_manager SHARED file_manager.cpp)编译库。使用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上都很难搞定,更不用说Windows和它可怕的多个堆了。
编辑:一旦files矢量超出范围,它肯定会崩溃。我目前的想法是,放入矢量的字符串在dll堆上分配,并在可执行文件堆上释放。如果是这种情况,有谁能告诉我更好的解决方法吗?