1

を使用して.cppファイル(それを呼びましょうstatinit.cpp)をコンパイルして実行可能ファイルにリンクしましたgcc。私のmain()関数はにありませんstatinit.cpp

statinit.cpp実行する必要のある静的初期化がいくつかあります。ただし、statinit.cpp自分のmain()、またはそれによって参照されるものから何かを明示的に参照することはありません。何が起こるか(私は推測します)、から作成されたリンクオブジェクトstatinit.cppは実行時にロードされないため、静的初期化が実行されず、コードの他の場所で問題が発生します(デバッグは非常に困難でしたが、最終的にはトレースしました)。

標準ライブラリ関数、リンカーオプション、コンパイラオプション、またはその要素の1つを参照せずに実行時にそのオブジェクトを強制的にロードできるものはありますか?

私がやろうと思ったのは、statinit.cppでダミー関数を定義し、それを参照するヘッダーファイルで宣言し、main()からそのダミー関数を呼び出すことmain()です。ただし、これは非常に醜い解決策であり、statinit.cpp自体に変更を加えないようにしたいと思います。

ありがとう、ダニエル

4

8 に答える 8

4

問題が何であるかは正確には明らかではありません。

C ++には、静的初期化子の概念がありません。
したがって、「ファイルスコープ」にオブジェクトがあると仮定します。

  • このオブジェクトがグローバル名前空間にある場合、main()が呼び出される前に構築され、main()が終了した後に破棄されます(アプリケーション内にあると想定)。
  • このオブジェクトが名前空間にある場合、オプションで実装は変数を遅延初期化することを選択できます。これは、最初に使用する前に完全に初期化されることを意味します。したがって、構築による副作用に依存している場合は、オブジェクトをグローバル名前空間に配置します。

このオブジェクトのコンストラクターが実行されないのは、アプリケーションにリンクされていないためです。これはリンカーの問題であり、言語の問題ではありません。これは、オブジェクトが静的ライブラリにコンパイルされ、アプリケーションが静的ライブラリに対してリンクされている場合に発生します。リンカは、アプリケーションから明示的に参照されているアプリケーション関数/オブジェクト(つまり、シンボルテーブル内の未定義のものを解決するもの)にのみロードされます。

この問題を解決するには、いくつかのオプションがあります。

  • 静的ライブラリは使用しないでください。
    • ダイナミックライブラリにコンパイルします(最近の標準)。
    • すべてのソースをアプリケーションに直接コンパイルします。
  • main内からオブジェクトへの明示的な参照を作成します。
于 2009-12-21T16:27:15.353 に答える
2

私は同じ問題に遭遇しました。

ファイルを書く、DoNotOptimizeAway.cpp

void NoDeadcodeElimination()
{
    // Here use at least once each of the variables that you'll need.
}

次に、NoDeadcodeElimination()から呼び出しますmain

編集:あるいは、リンカーオプションを編集して、使用されていない場合でも常にすべてをリンクするように指示することもできます。ただし、実行可能ファイルがはるかに大きくなるため、このアプローチは好きではありません。

于 2009-12-21T12:50:58.270 に答える
1

これらの問題、およびこれらの潜在的な解決策の問題はすべて、静的初期化について多くを保証できないという事実を中心に展開しています。それで、それは信頼できないので、それに依存しないでください!

静的な「InititalizeLibrary」タイプの静的関数を使用してデータを明示的に初期化します。今、あなたはそれが起こることを保証し、あなたがいつ電話をかけるかに基づいて他のコードとの関係でそれがいつ起こるかを保証します。

于 2009-12-21T13:42:19.887 に答える
1

これを行うC++のような方法の1つは、シングルトンを使用することです。

基本的に、オブジェクトへの参照を返す関数を記述します。強制的に初期化するには、関数内の静的オブジェクトにします。

漠然と次のようなクラス静的関数を作成します。

class MyClass {
   static MyClass& getObject()
   {
        static MyObject obj;
        return obj;
    }
};
于 2009-12-21T14:26:15.470 に答える
0

ldコマンドのマニュアルページを読み、-uオプションを確認します。statinit.cppが関数のように見えるものを定義している場合は、-uで名前を付けてみてください。それ以外の場合は、statinit.cppで定義されているデータオブジェクトを選択し、-uで名前を付けて、機能することを期待します。statinitのオブジェクトコードが含まれているライブラリの-lオプションの直前に-uオプションが来るように、コマンドラインを作成するのが最善だと思います。

于 2009-12-22T02:22:01.230 に答える
0

C ++を使用しているため、いつでもグローバルオブジェクト(つまり、のクラ​​スを参照するグローバル変数)を宣言できますstatinit.cpp。いつものように、コンストラクターは初期化時に呼び出され、オブジェクトはグローバルであるため、main()が呼び出される前に呼び出されます。走る。

ただし、非常に重要な注意点が1つあります。コンストラクターがいつ呼び出されるかについての保証はなく、これらの各コンストラクターがいつ呼び出されるかを明示的に順序付ける方法はありません。また、mainの実行中に割り当てられたすべてのメモリの割り当てが解除されたことを保証できなくなるため、これにより、メモリリークをチェックする試みが無効になる可能性があります。

于 2009-12-21T13:23:16.057 に答える
0

静的アイテムが初期化されなかったという問題ですか、それとも静的アイテムを使用する必要があるときに静的アイテムが初期化されなかったという問題ですか?

すべての静的初期化は、main()が実行される前に終了することになっています。ただし、静的オブジェクトを別の静的オブジェクトで初期化すると、問題が発生する可能性があります。(注:これは、intなどのプリミティブを使用している場合は適用されません)

たとえば、ファイルx.cppにある場合:

static myClass x(someVals);

そしてy.cppで:

static myClass y = x * 2; 

xが作成される前に、システムがyをインスタンス化しようとする可能性があります。その場合、初期化される前にxが0である可能性が高いため、「y」変数は0である可能性があります。

一般に、これに対する最善の解決策は、オブジェクトが最初に使用されたときにオブジェクトをインスタンス化することです(可能な場合)。ただし、上記で、そのファイルを変更することは許可されていないことに気づきました。そのファイルの値は他の場所で使用されていますか?また、それらの値へのアクセス方法を変更できますか?

于 2009-12-21T14:39:14.033 に答える
0

もちろん、ダイナミックライブラリソリューションが最適ですが、静的ライブラリ全体をリンカーオプションでリンクすることも可能であると言われています。

-Wl,-whole-archive

ライブラリの-lオプションの前、および

-Wl,-no-whole-archive

その後(他のライブラリ全体を含めることを避けるため)。

于 2009-12-22T07:55:23.757 に答える