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


34

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

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

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

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


3
あなたの質問に対する答えはわかりませんが、あなたの懸念は共有されていると言えます。潜在的な効率の最後のすべてのサイクルを絞り出すことよりもABIの安定性を重視しているため、プロジェクトでC ++を使用しない理由の鍵です。
ドナルフェローズ

2
区別してください。DLLsの間は難しいです。SOsの間は常に正常に機能しました。
ジャン・ヒューデック

1
厳密に言えば、これはC ++のみの問題ではありません。他の言語でこの問題が発生する可能性があります。
MrFox

2
@JanHudec SO間で、あなたが示すように魔法のように動作しないことを保証できます。シンボルの可視性と名前のマングリングが頻繁に機能する方法を考えると、問題からより絶縁されているかもしれませんが、1つの.soを異なるフラグなどでコンパイルし、プログラムで他のフラグとリンクできると仮定することは災害のレシピです。
sdg

3
@sdg:デフォルトのフラグとデフォルトの可視性で動作します。それらを変更してトラブルに巻き込まれた場合、それはあなたの問題であり、他の誰も問題ではありません。
ジャン・ヒューデック

回答:


20

すべての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にロードされるBoost.Pythonを使用して記述されたPython拡張を安全に生成できません。これは、グローバルCシンボルテーブルを備えたELFは、セグメンテーション違反を引き起こす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の取り組みを見て、今後数年でそこに何が現れるのかを見るだろう-何もしなければ驚くだろう。


素晴らしい反応!ClangがWindowsの互換性を改善し、適切なデフォルトの標準コンパイラを設定することを願っています。C ++のテキストインクルード/ヘッダーシステムは恐ろしいものです。モジュールがC ++コードの整理を簡素化し、コンパイル時間を無限に高速化し、ODR違反キャッチとコンパイラの相互運用性を改善する日を楽しみにしています。
アレッサンドロスタマート

3
個人的に、コンパイラー時間の大幅な増加を実際に期待しています。モジュール内ASTをすばやくトラバースすることは非常に困難であり、おそらくメモリ内の共有メモリキャッシュが必要になります。ただし、他のほとんどすべての問題は改善されます。ところで、ヘッダーファイルは間違いなく存在しています。現在のC ++モジュールには、1対1のヘッダーファイルへのインターフェイスファイルがあります。また、自動生成されたインターフェースファイルは正当なC ++であるため、レガシーヘッダーは単にCマクロをフィルター処理してインターフェースファイルとして吐き出します。いいね?
ニールダグラス

クール!私はモジュールについて多くの疑問を持っています。モジュールシステムは、テキストインクルージョンとシンボリックインクルージョンを考慮しますか?現在のincludeディレクティブでは、コンパイラはすべてのソースファイルに対して何万行ものコードを何度も再コンパイルする必要があります。モジュールシステムは、いつか前方宣言なしのコードを許可しますか?構築ツールを改善/緩和しますか?
アレッサンドロスタマート

2
-1は、すべてのサードパーティテンプレートが疑わしいことを示唆しています。構成の変更は、構成対象がテンプレートであるかどうかとは無関係です。
DeadMG

1
@Alessandro:提案されているC ++モジュールは、Cマクロを明示的に無効にします。テンプレートまたはnowtを使用できます。提案されたインターフェースは正当なC ++であり、単に自動生成され、再解析の速度のためにオプションでプリコンパイルすることができます。最後の2つの質問、私は実際に知りません:それは依存します:)
ニールダグラス

8

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

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

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

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

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


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


2
@DougT .: GCCはそれとは何の関係もありません。プラットフォームABIが持っています。ほとんどのUnicesで使用されるオブジェクト形式であるELFでは、共有ライブラリはすべての可視シンボルをエクスポートし、エクスポートするすべてのシンボルをインポートします。そのため、複数のライブラリで何かが生成された場合、動的リンカーはすべてに最初の定義を使用します。シンプルでエレガント、そして機能的。
ジャン・ヒューデック

1
@MartinBa:マージするものは何もありませんが、それが同じであり、そもそもマージされることになっていない限り、それは重要ではありません。はい、ELFプラットフォームで互換性のないコンパイラ設定を使用すると、どこでもどこでも同じ混乱が生じます。共有ライブラリを使用していない場合でも、ここでは多少話題から外れています。
ジャン・ヒューデック

1
@Jan-それはあなたの答えに関連しています。「... 1つの定義規則... Windows DLLはこの要件に違反しています...共有ライブラリは異なる動作をする(UNixで)...」と質問されましたが、質問は std-libの問題に関連しています(ヘッダーで定義)そして、Unixに問題がない理由はSOとDLLには関係ありませんが、実際には、Unix(明らかに)には標準ライブラリの互換バージョンが1つしかありませんが、Windows MSでは非互換(デバッグ)バージョンを選択しました(拡張チェックなどを使用)。
マーティンBa

1
@MartinBa:いいえ、Windowsに問題がある主な理由は、Windowsで使用されるエクスポート/インポートメカニズムがすべての場合にテンプレートクラスの静的メンバーとクラス障害を適切にマージできず、静的および動的にリンクされたシンボルをマージできないことです。複数のライブラリバリアントによってさらに悪化しますが、主な問題は、C ++がWindowsダイナミックリンカーにはないリンカーの柔軟性を必要とすることです。
ジャン・ヒューデック

4
DLLの仕様が破られ、Msftが「修正」するための対応する要求は、この意味合いが間違っていると思います。DLLがC ++の特定の機能をサポートしていないという事実は、DLL仕様の欠陥ではありません。DLLは、言語に依存せず、ベンダーに依存しないパッケージングメカニズムであり、エントリポイントをマシンコード(「関数呼び出し」)およびデータBLOBに公開するABIです。特定の言語の高度な機能をネイティブにサポートすることを意図したものではありませんでした。Msftの問題やDLL仕様のせいではなく、別の何かにしたい人もいます。
ユーロミチェリ

6

いや

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


2
ヘッダーシステムがこれに影響を与えるとは思わない。問題は、Windows DLLが1つの定義ルールに違反している(つまり、C ++仕様に従っていないため、C ++委員会はそれについて何もできない)、C ++委員会ができるWindowsの標準ランタイムのバリアントが非常に多いことです」どちらについても何もしません。
ジャン・ヒューデック

1
いいえ、そうではありません。どうして彼らは、仕様はそのようなものにさえ言及していません。それ以外は、(Windows)プログラムがWindows dllにリンクされている場合、ODRは満たされます。すべての可視(エクスポート)シンボルはODRに従う必要があります。
ポール・ミシャリック

@PaulMichalik C ++はリンク(フェーズ9)をカバーしており、少なくともDLL / SOのロード時リンクはフェーズ9に該当するようです。つまり、外部リンケージ(エクスポートされているかどうかに関係なく)がリンクされ、 ODR。LoadLibrary / dlopenとの動的リンクは、明らかにこれらの要件に該当しません。
bames53

@ bames53:私見、仕様はその種のステートメントを許可するにはあまりにも弱いです。A の.dll / .soが独自に「プログラム」として見ることができます。よりも、ルールは満たされました。実行時に他の「プログラム」をロードするようなものは、規格によってあまりに仕様が不十分であるため、これに関するステートメントはかなりarbitrary意的です。
ポール・ミシャリック

@PaulMichalik実行可能ファイルがロード時リンクを必要とする場合、ロード時リンクの前に外部エンティティが未解決のままになり、実行に必要な情報が失われます。LoadLibraryとdlopenは仕様の範囲外ですが、ロード時のリンクは明らかにフェーズ9の一部である必要があります。
bames5313年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.