特定の文字列リストを返す必要があるファイルを管理するための優れたライブラリがあります。私がこれを使用する唯一のコードは 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;
}
ライブラリは、add_library(file_manager SHARED file_manager.cpp) を使用して cmake でコンパイルされます。プログラムは、add_executable(file_manager_command_wrapper command_wrapper.cpp) を使用して別の cmake プロジェクトにコンパイルされます。これらのコマンドだけで、どちらにも指定されたコンパイル フラグはありません。
これで、プログラムは mac と linux の両方で完全に正常に動作します。問題は窓です。実行すると、次のエラーが発生します。
デバッグ アサーションに失敗しました!
...
式: _pFirstBlock == _pHead
これは、実行可能ファイルとロードされたdllの間のメモリヒープが分離されているためです。これは、メモリが一方のヒープに割り当てられ、もう一方のヒープで割り当て解除された場合に発生すると思います。問題は、私の人生にとって、何がうまくいかないのか理解できないことです. メモリは実行可能ファイルに割り当てられ、dll 関数への参照として渡されます。参照を介して値が追加され、それらが処理され、最終的に実行可能ファイルに割り当てが解除されます。
できればもっと多くのコードを公開したいと思いますが、私の会社の知的財産は公開できないと述べているため、上記のコードはすべて例にすぎません。
このエラーを理解するのに役立ち、デバッグして修正するための正しい方向に私を向けることができる、主題についてより多くの知識を持っている人はいますか? 残念ながら、私は Linux で開発しているため、Windows マシンをデバッグに使用することはできません。変更を gerrit サーバーにコミットし、ジェンキンを介してビルドとテストをトリガーします。コンパイルおよびテスト時に出力コンソールにアクセスできます。
stl 以外の型を使用して、c++ のベクトルを char** にコピーすることを検討しましたが、メモリ割り当ては悪夢であり、Windows はもちろん Linux でもうまく動作させるのに苦労していました。それは恐ろしい複数のヒープです。
編集: ファイル ベクトルが範囲外になるとすぐにクラッシュします。私の現在の考えでは、ベクトルに入れられた文字列は dll ヒープに割り当てられ、実行可能ヒープで割り当て解除されます。この場合、誰かがより良い解決策について教えてくれますか?