STLを複数の共有ライブラリに静的にリンクすることの何が問題になっていますか?


8

ここにシナリオがあります:

  1. libA.soとlibB.soは両方とも同じSTLに静的にリンクします。
  2. libA.soには、std :: stringを返すパブリックAPIがあります。
  3. libB.soはこの関数を呼び出し、文字列のコピーを受け取ります。
  4. 文字列のlibB.soのコピーがスコープ外になると、文字列のデストラクタが呼び出されます。
  5. コピーされた文字列を解放しようとするアプリケーションセグメントフォールト。

このように静的にリンクすることは悪いことを他の場所で読んだことがありますが、なぜそれが悪いのかをもっと理解したいと思います。上記のシーケンスがクラッシュする理由を誰かが説明できますか?


1
上記のシーケンスがクラッシュするのはなぜですか?
ドクターブラウン

回答:


8

これについて非常に注意深く考えましょう。libA.soはSTLと静的にリンクされています。ただし、STLは単独では存在せず、Cランタイム(CRT)が必要です。どちらもlibstdc ++。a静的ライブラリにあります。つまり、libA.soとlibB.soは別々のCRTデータ構造を持っています。特に、libA.soが使用するヒープは、libB.soが使用するヒープとは異なります。libAのランタイムヒープから文字列を割り当て、libBのランタイムから解放しようとしても、libBのランタイムには文字列を割り当てるレコードがないため、単に機能しません。文字列を正しく破棄する唯一の方法は、libA.so内のデストラクタを呼び出すことです。

質問するかもしれませんが、libB.soは文字列のコピーを受け取りますよね?はい、そうですが、誰がこのコピーを割り当てましたか?libAのランタイムのコンテキスト内でコピーコンストラクターを使用して割り当てられています。

それでも、libB.soの文字列は引き続き使用できます。そこから破壊することはできません。

libBに文字列へのポインタを受信させ、libBのランタイムのコンテキスト内でそのコピーを作成することもできます。そのコピーはlibBによって破壊される可能性があります。

そして、それが静的リンクが時々悪い理由です。


1
ここで「文字列」が何を指しているのか分かりません。話がaのstd::string場合、問題は単に存在しません:独自のメモリで管理されているメモリで文字列のコピーlibB.so受け取るか、で文字列への参照/ポインタを受け取り、削除しようとしません。独自のメモリからの文字列。libA.so
Konrad Rudolph

1
@KonradRudolphとりわけ、(N)RVO最適化は、返された文字列がlibA.soによって構築され、libB.soによって破棄される状況を作り出します。
Sjoerd 2014年

この答えは実際に私が見たものと一致しているので、私が完全に理解していない部分は、各ライブラリのヒープの動作方法だと思います。最初は、ヒープはプロセス内の単一のグローバルなものだと思っていましたが、それを説明する方法では、複数のヒープがあるように聞こえます。これは、(libc内の)アロケータの実装方法の問題ですか、それともこれを制御するもの(ローダーなど)がありますか?
user1509041 2014年

プロセスにグローバルヒープがあるのか​​複数のヒープがあるのか​​は、使用されている特定のCRT実装によって異なります。私は両方のケースを見ました。複数のヒープがあるようです。ローダーはヒープとは何の関係もありません。
Hadi Brais 14年

1
@AymanSalahはい、それはうまくいくはずです。OSのバージョンは、言語標準APIではなくOS固有のAPIを使用している場合にのみ重要です。
Hadi Brais

3

STLはいわゆる「ステートフル」(「ステートレス」とは反対)であり、内部に静的なものがあります。libA.soとlibB.soの両方にSTLを静的にリンクすると、実行時にメモリにSTLライブラリの2つのインスタンスが取得されます(静的なものの2つのコピーを使用)。これらの2つのコピーはそれぞれ、割り当てられたリソースを個別に管理し、ライブラリの1つのインスタンスに割り当てられたリソースを別のインスタンスで解放することはできません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.