web-dev-qa-db-ja.com

C ++ 11は、動的/共有ライブラリー境界間でstd libオブジェクトを渡すことに関する懸念に対処しましたか? (つまり、dllなど)?

C++に関する私の主な不満の1つは、動的ライブラリ(つまり、dll/so)の境界の外にstdライブラリオブジェクトを渡すことが実際にどれほど難しいかです。

Stdライブラリは多くの場合ヘッダーのみです。これは、いくつかの素晴らしい最適化を行うのに最適です。ただし、dllの場合は、さまざまなコンパイラ設定でビルドされることが多く、stdライブラリコンテナの内部構造/コードに影響を与える可能性があります。たとえば、MSVCでは、1つのdllがイテレータデバッグをオンにしてビルドされ、別のdllはそれをオフにしてビルドされます。これらの2つのDLLは、stdコンテナーを渡す際に問題が発生する可能性があります。インターフェイスでstd::stringを公開した場合、クライアントがstd::stringに使用しているコードが、ライブラリのstd::stringと完全に一致することは保証できません。

これにより、問題や頭痛などのデバッグが困難になります。組織のコンパイラ設定を厳密に制御してこれらの問題を回避するか、これらの問題のない単純なCインターフェイスを使用します。または、クライアントが使用する予定のコンパイラ設定をクライアントに指定します(別のライブラリが他のコンパイラ設定を指定している場合、これは問題になります)。

私の質問は、C++ 11がこれらの問題を解決するために何かしようとしたかどうかです。

34
Doug T.

あなたは正しいです。どんなSTL-実際には、テンプレート化されたサードパーティのライブラリからの何か-は、どんなパブリックC++ APIでも避けるのが最善です。また、 http://www.ros.org/reps/rep-0009.html#definition にあるルールの長いリストに従って、パブリックC++ APIのプログラミングを面倒にするABIの破損を防ぐこともできます。

C++ 11に関する答えは「いいえ」であり、この標準はそれに触れていません。より興味深いのはなぜですか?答えは、C++ 17がそれに非常に触れているためです。C++モジュールを実装するには、エクスポートされたテンプレートが機能する必要があり、そのためには、完全なASTをディスクに保存してから、呼び出し元に依存するルックアップを実行して、大規模なC++プロジェクトでのODR違反の多くのケースを処理します。これには、GCCおよびELFコードが多数含まれています。

最後に、MSVCに対する嫌悪感やGCCへの賛成コメントがたくさんあります。これらは非常に誤った情報に基づいています-ELF上のGCCは、根本的かつ取り返しのつかないほど、有効で正しいC++コードを生成することができません。この理由は多種多様ですが、1つの事例を簡単に引用します。ELFのGCCは、Boost.Pythonを使用して記述されたPython拡張機能を安全に作成できません。 PythonはPythonにロードされます。これは、グローバルCシンボルテーブルを備えたELFが、segfaultを引き起こすODR違反を防ぐ設計では単純に実行できないためです。非常に高速なプロセスの初期化時間。さらに多くの問題があります。最近回答したStackOverflowを参照してください https://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055 たとえば、C++例外のスローがELFで根本的に壊れて回復できない場合。

最後のポイント:異なるSTLの相互運用に関して、これは、いくつかのSTL実装に緊密に統合されているサードパーティのライブラリを混在させようとする多くの大企業ユーザーにとって大きな痛みです。唯一の解決策はC++がSTL相互運用を処理するための新しいメカニズムであり、それらが機能している間は、コンパイラ相互運用も修正して、たとえば、MSVC、GCC、およびclangコンパイル済みオブジェクトファイルを混在させることができ、すべてが機能する。私はC++ 17の取り組みを見て、今後数年間でそこで何が起きるかを確認します-何も起こらなかったら私は驚きます。

21
Niall Douglas

仕様には、この問題はありませんでした。これは、「1つの定義ルール」と呼ばれる概念があり、実行中のプロセスで各シンボルが1つの定義のみを持つことを義務付けているためです。

Windows DLLはこの要件に違反しています。だからこそ、これらすべての問題があります。したがって、C++標準化委員会ではなく、Microsoftが修正する必要があります。共有ライブラリの動作が異なり、デフォルトでは1つの定義ルールに準拠しているため、Unixにはこの問題はありませんでした(明示的に違反することができますが、明らかに余裕があり、いくつかの余分なサイクルを絞る必要がある場合にのみ行います)。

Windows DLLは、次の理由により、1つの定義ルールに違反しています。

  • 静的リンク時にシンボルがどの動的ライブラリから使用されるかをハードコードし、それらを定義するライブラリ内で静的にシンボルを解決します。したがって、同じウィークシンボルが複数の共有ライブラリとそれらのライブラリで生成され、単一のプロセスで使用される場合よりも、動的リンカーはそれらのシンボルをマージする機会がありません。通常、このようなシンボルは、テンプレートインスタンスの静的メンバーまたはクラス障害であり、異なるDLLのコード間でインスタンスを渡すときに問題が発生します。
  • コンパイル時にすでにシンボルがダイナミックライブラリからインポートされるかどうかをハードコードします。したがって、一部のライブラリに静的にリンクされたコードは、同じライブラリに動的にリンクされたコードと互換性がありません。

ELF形式のエクスポートを使用するUnixは、最初の問題を回避するためにすべてのエクスポートされたシンボルを暗黙的にインポートし、2番目の問題を回避するための静的リンク時間まで、静的に解決されたシンボルと動的に解決されたシンボルを区別しません。


もう1つの問題はコンパイラフラグです。この問題は、複数のコンパイルユニットから構成されるプログラムに存在します。動的ライブラリが関与する必要はありません。ただし、Windowsの方がはるかに悪いです。 Unixでは、静的にリンクするか動的にリンクするかは関係ありません。いずれにせよ標準ランタイムを静的にリンクすることはなく(Linuxでは違法である可能性もあります)、特別なデバッグランタイムがないため、1つのビルドで十分です。しかし、Microsoftが静的および動的リンク、デバッグ、リリースランタイム、およびその他のオプションを実装した方法は、必要なライブラリバリアントの組み合わせが爆発的に増加したことを意味します。ここでも、C++言語の問題ではなく、プラットフォームの問題です。

8
Jan Hudec

番号。

ヘッダーシステム(モジュールと呼ばれ、これに影響を与える可能性がある機能)を置き換えるために多くの作業が行われていますが、大きなものではありません。

6
Klaim