5

C++ で、さまざまなクラス、関数、ファイルで使用できる非ローカル const 文字列を定義したい場合、私が知っているアプローチは次のとおりです。

  1. define ディレクティブを使用します。

    #define STR_VALUE "some_string_value"
    
  2. const クラスのメンバー変数。

    class Demo {  
    public:  
      static const std::string ConstStrVal;  
    };  
    // then in cpp  
    std::string Demo::ConstStrVal = "some_string_value";  
    
  3. const クラスのメンバー関数。

    class Demo{  
    public:  
      static const std::string GetValue(){return "some_string_value";}  
    };  
    

私がはっきりしていないのは、2番目のアプローチを使用する場合、変数 ConstStrVal は、実際にコードで使用される前に常に「some_string_value」に初期化されるということです。「静的初期化順序の大失敗」のため、これについて心配しています。この問題が有効である場合、なぜ誰もが 2 番目のアプローチを使用しているのですか?

2 と 3 のどちらが最善のアプローチですか? #define ディレクティブはスコープを尊重しないことを私は知っています。ほとんどの人はそれをお勧めしません。

ありがとう!

4

4 に答える 4

5

2番目のアプローチを使用する場合、変数 ConstStrVal は、実際にコードで使用される前に常に「some_string_value」に初期化されますか?

いいえ

初期化される値と初期化の順序によって異なります。ConstStrValグローバルコンストラクタがあります。

コンストラクターを使用して別のグローバル オブジェクトを追加することを検討してください。

static const std::string ConstStrVal2(ConstStrVal);

順序は言語によって定義されておらず、ConstStrVal2のコンストラクターは が構築される前に呼び出される場合がありますConstStrVal

初期化の順序はさまざまな理由で異なる場合がありますが、多くの場合、ツールチェーンによって指定されています。リンクされたオブジェクト ファイルの順序を変更すると、(たとえば) イメージの初期化の順序が変更され、エラーが発生する可能性があります。

なぜ誰もが2番目のアプローチを使用しているのですか?

多くの人が非常に正当な理由で他のアプローチを使用しています…</p>

2 と 3 のどちらが最善のアプローチですか?

番号 3. 次のように複数の構造を回避することもできます。

class Demo {
public:  
  static const std::string& GetValue() {
    // this is constructed exactly once, when the function is first called
    static const std::string s("some_string_value");
    return s;
  }  
};  

注意: このアプローチでは、 に見られる初期化の問題が発生する可能性がありますConstStrVal2(ConstStrVal)。ただし、初期化の順序をより細かく制御でき、グローバル コンストラクターを持つオブジェクトと比較すると、移植可能な問題を簡単に解決できます。

于 2012-04-21T06:07:32.290 に答える
1

一般に、私 (および他の多くの人) は、変数よりも値を返すために関数を使用することを好みます。これは、関数の方が将来の拡張に対する柔軟性が高いためです。成功するソフトウェア プロジェクトに費やされる時間のほとんどは、コードを最初に記述することではなく、コードの維持と強化に費やされることを忘れないでください。今日の定数が明日のコンパイル時定数ではないかどうかを予測するのは困難です。いつか設定ファイルから読み込まれるかもしれません。

そのため、私はアプローチ 3 をお勧めします。これは、現時点で必要なことを実行し、将来の柔軟性を高めるためです。

于 2012-04-21T05:54:20.813 に答える
0

他の方法では達成できない神聖な目的を達成しようとしている場合を除き、C++ でプリプロセッサ ディレクティブを使用しないでください。

標準(3.6.2)から:

静的ストレージ期間 (3.7.1) を持つオブジェクトは、他の初期化が行われる前にゼロで初期化されます (8.5)。静的な保存期間を持つ参照と、静的な保存期間を持つ POD 型のオブジェクトは、定数式 (5.19) で初期化できます。これは、定数の初期化と呼ばれます。ゼロ初期化と定数初期化をまとめて静的初期化と呼びます。他のすべての初期化は動的初期化です。静的初期化は、動的初期化が行われる前に実行されます。オブジェクトの動的初期化は、順序付きまたは順序なしのいずれかです。明示的に特殊化されたクラス テンプレートの静的データ メンバーの定義には、初期化の順序があります。その他のクラス テンプレートの静的データ メンバー (つまり、暗黙的または明示的にインスタンス化された特殊化) には、順序付けされていない初期化があります。名前空間スコープで定義された他のオブジェクトには、初期化の順序がありました。単一の翻訳単位内で定義され、順序付けされた初期化を持つオブジェクトは、翻訳単位での定義の順序で初期化されます。初期化の順序は、順序付けされていない初期化のオブジェクトと、異なる翻訳単位で定義されたオブジェクトでは規定されていません。

したがって、2 の運命は、変数が静的に初期化されているか動的に初期化されているかによって異なります。たとえば、具体的な例では、const char * Demo::ConstStrVal = "some_string_value";(値がプログラム内で一定のままである場合はさらに良いconst char Demo::ConstStrVal[])を使用すると、何があっても初期化されることを確認できます。のstd::string場合、それは POD タイプではないため、確信が持てません (これについては確信が持てませんが、かなり確信しています)。

3番目の方法では確実に確認でき、ジャスティンの回答の方法では不要な構造がないことを確認できます。ただし、静的メソッドには、呼び出しごとに変数が既に初期化されているかどうかを確認するという隠れたオーバーヘッドがあることに注意してください。単純な定数を返す場合、関数はおそらくインライン化されるため、値を返すだけの方が確実に高速です。

以上のことから、静的初期化に依存しないようにプログラムを作成するようにしてください。静的変数は利便性が高いと考えられていますが、初期化の順序を調整する必要がある場合は、もはや便利ではありません。

于 2012-04-21T06:23:12.333 に答える
0

C++ でプリプロセッサを使用しないでください。また、クラスには文字列があり、他のクラスではそれが必要なのはなぜですか? より良いカプセル化を可能にするために、クラスの設計を再評価します。このグローバル文字列が絶対に必要な場合は、globals.h/cpp モジュールを追加して、そこで文字列を次のように宣言/定義することを検討します。

const char* const kMyErrorMsg = "This is my error message!";
于 2012-04-21T06:03:42.983 に答える