1

さまざまな翻訳単位の特定の静的オブジェクトの前に初期化 (構築) する必要があるグローバルな静的 std::vector がある場合を検討しています。

これを処理する方法を調べると、2 つの提案された解決策に出くわします。

  1. グローバル静的オブジェクトの代わりに使用されるグローバル関数に静的オブジェクトを配置します。
  2. シュヴァルツカウンター

Schwarz カウンターの使用に関する私の懸念は、std::vector が 2 回初期化されることです。このリンクから、「グローバルオブジェクトが一度だけ初期化され、最初に使用される前に、それを使用する翻訳単位の数を維持するための便利な手法」が得られます。

グローバルが一度だけ初期化されるのはどのように機能しますか? 私の推論では、2回初期化されます。静的初期化の通常の過程で 1 回、および Schwarz カウンターの最初のインスタンスが初期化されるときに 1 回。

関連して、Schwarz カウンター コンストラクターの初期化コードはどのようになりますか? 新しいプレースメントを使用することしか考えられません。

4

3 に答える 3

1

過去にそれをどのように実装したかしか言えません。何もしない特別な「ノーオペレーション」コンストラクターを設計し、Schwartz カウンターで新しい配置を使用します。何かのようなもの:

class ForUseAsStatic
{
public:
    enum MakeCtorNoop { makeCtorNoop };
    ForUseAsStatic();   //  normal ctor, called by Schwartz counter.
    ForUseAsStatic( MakeCtorNoop );
                        //  no-op constructor, used when
                        //  defining the variable.
};

正式には、これは保証されていません。コンストラクターを呼び出す直前に、コンパイラーがメモリーを 0 に再度設定することは許可されていますが、そうするコンパイラーは聞いたことがありません。

コンストラクターによってテストされた、クラス自体に何らかのフラグを設定することも可能です。もちろん、これは静的オブジェクトに対してのみ有効です(機能するために初期化が必要ないため)。

別の考えられる手法 (一部のライブラリで使用されているのを見てきました) は、アセンブラーでオブジェクトのメモリを宣言するか、コンパイラにアライメントを強制する手段がある場合はバイト配列として宣言することです。通常、データ名はマングルされないため、正式には未定義の動作であっても、これは通常は機能します。(もちろん、標準ライブラリの場合、ライブラリの作成者はコンパイラで拡張機能を要求して、問題を解決することができます。)

最後に、今日では、シングルトンのイディオムまたはそれに類似したものが一般的にそのような回避策よりも好まれています。myobj().xxxだけではなく ,を書かなければならないということですがmyobj.xxx、これは一般的に問題とは感じられません。

于 2013-08-12T17:57:35.813 に答える
0

別のレベルの間接化を使用できます。グローバル変数をベクトルへのポインター (ゼロで初期化されます) にし、カウンターnewをベクトルにして、結果をポインターに格納します。

于 2013-08-12T19:10:01.320 に答える