我有一个很好的库来管理需要返回特定字符串列表的文件。由于我将使用它的唯一代码将是 C++(和 Java,但这是通过 JNI 使用 C++)我决定使用标准库中的向量。库函数看起来有点像这样(其中 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 中都可以正常工作。问题是窗户。运行时,我收到此错误:
调试断言失败!
...
表达式:_pFirstBlock == _pHead
我发现并理解这是因为可执行文件和加载的 dll 之间存在单独的内存堆。我相信当内存在一个堆中分配并在另一个堆中释放时会发生这种情况。问题是,对于我的生活,我无法弄清楚出了什么问题。内存在可执行文件中分配并作为引用传递给 dll 函数,通过引用添加值,然后处理这些值并最终在可执行文件中释放。
如果可以,我会透露更多代码,但我公司的知识产权声明我不能,所以以上所有代码都只是示例。
任何对该主题有更多了解的人都可以帮助我理解这个错误,并指出我调试和修复它的正确方向吗?不幸的是,自从我在 linux 上开发以来,我无法使用 windows 机器进行调试,然后将任何更改提交到通过 jenkins 触发构建和测试的 gerrit 服务器。我可以在编译和测试时访问输出控制台。
我确实考虑过使用非 stl 类型,将 c++ 中的向量复制到 char**,但是内存分配是一场噩梦,我很难让它在 linux 上很好地工作,更不用说 windows,而且它是可怕的多堆。
编辑:一旦文件向量超出范围,它肯定会崩溃。我目前的想法是放入向量中的字符串在dll堆上分配并在可执行堆上释放。如果是这种情况,有人可以告诉我更好的解决方案吗?