У меня есть хорошая библиотека для управления файлами, которые должны возвращать определенные списки строк. Поскольку единственный код, который я когда-либо буду использовать, будет С++ (и Java, но с использованием С++ через JNI), я решил использовать вектор из стандартных библиотек. Функции библиотеки выглядят примерно так (где 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);
}
}
Причина, по которой я использовал вектор в качестве ссылки вместо возвращаемого значения, является попыткой сохранить распределение памяти в здравом смысле и потому, что окна были действительно недовольны тем, что у меня есть extern "C" вокруг возвращаемого типа С++ (кто знает, почему, я понимаю, что все extern "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). Программа скомпилирована в отдельный проект cmake, используя add_executable (file_manager_command_wrapper command_wrapper.cpp). Флагов компиляции не указано ни для одного, ни для тех команд.
Теперь программа отлично работает как в mac, так и в linux. Проблема - это окна. При запуске я получаю эту ошибку:
Не удалось выполнить отладочную проверку!
...
Выражение: _pFirstBlock == _pHead
Это, я выяснил и понял, из-за разброса памяти между исполняемыми файлами и загруженными DLL. Я считаю, что это происходит, когда память распределяется в одной куче и освобождается в другой. Проблема в том, что для жизни я не могу понять, что происходит не так. Память выделяется в исполняемом файле и передается как ссылка на функцию dll, значения добавляются через ссылку, а затем обрабатываются и, наконец, освобождаются обратно в исполняемый файл.
Я бы раскрыл больше кода, если бы мог, но интеллектуальная собственность в моей компании утверждает, что я не могу, поэтому весь приведенный выше код - всего лишь примеры.
Кто-нибудь, у кого больше знаний о предмете, который может помочь мне понять эту ошибку, и указать мне в правильном направлении, чтобы отлаживать и исправлять ее? К сожалению, я не могу использовать Windows-машину для отладки, так как я разрабатываю Linux, а затем фиксирую любые изменения на сервере gerrit, который запускает сборки и тесты через jenkins. У меня есть доступ к выходной консоли при компиляции и тестировании.
Я рассмотрел использование не-stl-типов, скопировав вектор в С++ на char **, но выделение памяти было кошмаром, и я изо всех сил пытался заставить его работать красиво на linux, не говоря уже о окнах, и это ужасно много отвалы.
EDIT: он определенно сбой, как только вектор файлов выходит из области видимости. Моя текущая мысль состоит в том, что строки, помещенные в вектор, выделяются на кучу dll и освобождаются от исполняемой кучи. Если это так, может ли кто-нибудь просветить меня относительно лучшего решения?