17

私は 2 つの dll エクスポート クラス A と B を持っています。A の宣言には、次のようなシグネチャで std::vector を使用する関数が含まれています。

class EXPORT A{
 // ...
 std::vector<B> myFunction(std::vector<B> const &input);
};

(EXPORT は、それに応じて _declspec(dllexport )/ _declspec(dllimport) を配置する通常のマクロです。)

DLL インターフェイスで STL クラスを使用することに関連する問題について読んで、要約すると次のようになります。

  • DLL インターフェイスで std::vector を使用するには、その DLL のすべてのクライアントを同じコンパイラの同じバージョンでコンパイルする必要があります。これは、STL コンテナーがバイナリ互換でないためです。さらに悪いことに、クライアントがその DLL を他の DLL と組み合わせて使用​​することによっては、システム アップデート (Microsoft KB パッケージなど) がインストールされたときに、「不安定な」DLL API によってこれらのクライアント アプリケーションが壊れる可能性があります (本当に?)。

  • std::vector<B>上記にもかかわらず、必要に応じて、次のようにエクスポートすることにより、DLL API で std::vector を使用できます。

    template class EXPORT std::allocator<B>;
    template class EXPORT std::vector<B>;
    

    ただし、これは通常、std::vector を A のメンバーとして使用する場合のコンテキストで言及されます(http://support.microsoft.com/kb/168958)。

  • 次の Microsoft サポート記事では、DLL で作成された std::vector オブジェクトに、実行可能ファイル内からポインターまたは参照を介してアクセスする方法について説明しています (http://support.microsoft.com/default.aspx?scid=kb;EN-US; Q172396)。使用する上記のソリューションtemplate class EXPORT ...も適用できるようです。ただし、最初の箇条書きでまとめた欠点は残っているようです。

  • この問題を完全に取り除くには、std::vector をラップしてmyFunction、PIMPL などの署名を変更する必要があります。

私の質問は次のとおりです。

  • 上記の要約は正しいですか、それともここで重要なことを見逃していますか?

  • クラス 'A' のコンパイルで警告 C4251 が生成されないのはなぜですか (クラス 'std::vector<_Ty>' には、... のクライアントが使用する dll-interface が必要です)? コンパイラの警告をオフにしておらずmyFunction、エクスポートされたクラス A (VS2005 を使用) で std::vector を使用しても警告が表示されません。

  • A で正しくエクスポートするには何をする必要がありますmyFunctionか? std::vector<B>Bのアロケータをエクスポートするだけで実行可能ですか?

  • std::vector を値で返すことの意味は何ですか? 別のコンパイラ (-version) でコンパイルされたクライアント実行可能ファイルを想定しています。ベクトルがコピーされた場所で値渡しを返すときに問題が解決しませんか? はい。同様に、std::vector を定数参照として渡す場合: std::vector<B>(別のコンパイラ (-version) でコンパイルされた実行可能ファイルによって構築された可能性がある) にアクセスできますmyFunctionか? 私はまたそうだと思います..

  • 上記の最後の箇条書きが本当に唯一のクリーンな解決策ですか?

フィードバックをお寄せいただきありがとうございます。

4

2 に答える 2

2

残念ながら、あなたのリストは非常に的を射ています。この根本的な原因は、DLL から DLL または DLL から EXE がオペレーティング システムのレベルで定義されているのに対し、関数間のインターフェイスはコンパイラのレベルで定義されていることです。ある意味では、クライアントとサーバーにバイナリ互換性がない場合のクライアントとサーバーのやり取りに似ています (やや簡単ですが)。

コンパイラは、特定のオペレーティング システムで実行される DLL のインポートとエクスポートの方法にできることをマップします。言語仕様は、ユーザー定義型や組み込み型のバイナリ レイアウトに関してコンパイラに多くの自由を与えるため (int最小サイズ要件が満たされている限り、正確なサイズはコンパイラに依存することを思い出してください)、インポートまた、DLL からのエクスポートは、バイナリ レベルの互換性を実現するために手動で行う必要があります。

同じコンパイラの同じバージョンを使用する場合、上記の最後の問題は問題になりません。ただし、別のコンパイラが登場するとすぐに、すべての賭けはオフになります。単純に型指定されたインターフェイスに戻り、ラッパーを導入して、コード内の見栄えの良いインターフェイスを維持する必要があります。

于 2012-05-13T16:26:06.607 に答える