4

ここでは、 Which header ?の下に次のステートメントがあります。:

最後に<iostream>、8 つの標準グローバル オブジェクト (cin、cout など) を提供します。これを正しく行うために、このヘッダーは<istream>および<ostream>ヘッダーの内容も提供しますが、他には何も提供しません。このヘッダーの内容は次のようになります

#include <ostream>
#include <istream>

namespace std
{
    extern istream cin;
    extern ostream cout;
    ....

    // this is explained below
    static ios_base::Init __foo;    // not its real name
}

ここで、前述のランタイム ペナルティがあります。グローバル オブジェクトは、独自のコードで使用する前に初期化する必要があります。これは標準で保証されています。他のグローバル オブジェクトと同様に、一度だけ初期化する必要があります。これは通常、上記のような構造で行われ、ネストされたクラス ios_base::Init が標準で指定されているのは、まさにこの理由からです。

それはどのように機能しますか?ヘッダーはどのコードよりも前にインクルードされるため、__foo オブジェクトはどのオブジェクトよりも前に構築されます。(グローバル オブジェクトは、宣言された順序で構築され、逆の順序で破棄されます。) コンストラクタが最初に実行されると、8 つのストリーム オブジェクトが設定されます。

私の質問: ヘッダー ファイル<iostream>を複数のファイルに含める場合、上記のスキームは、オブジェクト、などの定義が1 つだけ.cppであることをどのように保証しますか?cincout

4

1 に答える 1

3

それは本当にそれを保証するものではありません。1 つの定義の問題は、ライブラリの一部である .cpp ファイルでストリーム オブジェクトを 1 回定義するだけで解決されます。問題のコードには、標準ストリームの宣言が含まれているだけです。

保証されているのは、オブジェクトが使用される前に初期化されることです。C++ のグローバル オブジェクトに関する 1 つの問題は、それら各 .cpp ファイル内で順番に初期化される一方で、リンカーが別のファイルからオブジェクトを配置する順序がわからないことです。これにより、あるオブジェクトが初期化される前に別のオブジェクトを使用しようとすると問題が発生する可能性があり、正確な順序がわからない場合があります -静的初期化順序の失敗を参照してください。

ここで使用されている 1 つの回避策はInit、ストリーム オブジェクトを宣言するヘッダーにオブジェクトを配置することです。ストリームを使用する前にヘッダーを含める必要があるため、このInitオブジェクトがファイルの先頭にあり、ストリームを使用する可能性のある他のオブジェクトの前に構築されることがわかっています。

これで、クラスのコンストラクターがInitストリーム オブジェクトの初期化を担当します。これは早い段階で一度だけ行う必要があります。正確な方法は各実装に任されていますが、コードは、作成されたオブジェクトの数を追跡するカウンターを使用することを示唆していInitます (おそらく最初のオブジェクトを特別に処理します)。

これは、標準言語のみを使用してこれを行う 1 つの方法にすぎません。一部の実装には、#pragma s やinit_priorityディレクティブなど、リンカーがユーザー コードの前にライブラリ コードを配置するよう説得するための他のトリックがあります。その場合、Initクラスを使用せずに魔法で機能します。

于 2013-02-16T12:44:39.287 に答える