2016-12-12 27 views
2

大きなファイルのファイルがConstants.hで、約200個の変数(が大部分は)が宣言され、初期化されています。私は名前空間を使用しています。ヘッダファイルの宣言と初期化が多すぎますC++

方法1:

//Constants.h 

#ifndef CONSTANTS_H_ 
#define CONSTANTS_H_ 

namespace LibConstants 
{ 
    const int a = 12; 
    const std::string theme[2]; = {"themeA", "themeB"}; 
    const int arr[2] = {1, 2}; 
    // and around 200 more declarations with initialization 
} 
#endif 

この.hファイルには、ほぼすべての.cppファイルだけ非常に最小限の変数がLibConstants::theme[0]のように使用されている各時間で#includeです。

私のやり方はうまく動作しますが、は不必要にメモリを割り当てますか? というアプローチに従って、ファイルを.hに定義し、.cppに初期化するだけですか?以下のコードで

同様: 方法2:

//Constants.h 

#ifndef CONSTANTS_H_ 
#define CONSTANTS_H_ 

namespace LibConstants { 

    std::string getMyTheme(int arg); 
    std::string getMyThemeName(int arg); 

    const int a; 
    const std::string theme[2]; 
    const int arr[2]; 
    // and around 200 more declarations with initialisation 
}; 
#endif 

ようにそれを使用したCPPファイル

//Constants.cpp 

#include LibConstants.h 
using namespace LibConstants { 
    std::string getMyTheme(int arg) { 
     theme[2] = {"themeA", "themeB"}; 
     return theme[arg]; 
    } 
    std::string getMyThemeName(int arg) { 
     ... 
    } 
} 

に初期化します

ここでは、ヘッダファイル内でconst std::string st[2];と宣言されている配列を除いて、不要な変数に不要なメモリを割り当てることはありません。

ここで、「arg = 0」は実行時関与です。いくつかの変数が実行時に依存しないが、コンパイル時にのみ対応する場合は、対応する.cppファイルのプレースホルダの値を単に置き換えることになりますか?

私が間違っているところで私を修正してください。

+0

ヘッダーまたはソースファイルで宣言して初期化するかどうかに関係なく、コンパイル時定数はほとんどの実装でデータセグメントに移動します。例えば、あなたは 'int a [] = {/ *大きな配列* /}'を持っているとします。 'a'は定数ではありませんが、まだ初期化されていますが、プログラムはまだロードしなければなりません。だからこの場合、私はそれが重要な違いをもたらすとは思わない。一方、変数がコンストラクタまたは他の手段によって実行時の実行を初期化する必要がある場合。それを関数にラップし、オンデマンドで作成する方がよいでしょう。 –

+0

@YanZhou速い返信をありがとう。つまり、両方のコンパイル時にメモリを消費するのではなく、各.cppファイル内のプレースホルダを置き換えるだけなので、上記の方法はほぼ同じです。 – myDoggyWritesCode

+0

いいえ、回答を記入してください。 –

答えて

2

std::stringの例を参照してください。

namespace Constants { 
const std::string str = "A not very short string"; 
} 

strがクラス型であり、それはコンストラクタを有し、それは短い文字列の最適化は、その実装に使用されている場合を除く。その場合でも、それだけ適用(その内容を格納するためにメモリを割り当てる必要があり、検討〜、まあ、「短い文字列」)。名前空間スコープ変数として宣言されています。そのため、プログラムは起動時にこの変数を構築する必要があります。この変数が宣言されているすべてのプログラムは、メモリを割り当て、その内容を初期化する必要があります。それはあなたのパフォーマンスにどれだけ影響を与えるかによって、おそらくあなたが望まないオーバーヘッドです。一方

、あなたが持っている場合は、

const std::string &str() 
{ 
    const static std::string s = "A not very short string"; 

    return s; 
} 

は今、あなたは、静的ローカル変数を持っています。関数の最初のエントリで初期化されます。それは一度だけ初期化されます。 strが呼び出されない場合、それはまったく初期化されません。

ただし、文字列リテラル"A not very short string"はまだメモリを占有しています。どこにどのようにストアされているかは実装定義です。通常はデータセグメント内にあり、影響は通常最小です。

クラスの種類とは異なります。基本的な型、特にヘッダの整数型を定義することが望ましい。

例えば、

namespace Constants { 
constexpr int x = 10; 
} 

最適化コンパイラは、最も可能性の高い変数xを保存しないであろうと、その内容は全く10。代わりに、xが使用される場合は、10に置き換えられ、場合によっては命令オペコード(いわゆる即値オペランド)にコード化されます。もちろん、これは実装の詳細です。そして、そのような最適化はすべてのコンパイラに依存することはできません。 xのアドレスを使用するかODRを使用すると、コンパイラはこの変数のための空き領域を確保するよう強制されます。しかし、ボトムラインは、ヘッダーにこの定数を宣言することで、外部ソースファイルで定義するよりも悪化する可能性は非常に低いです。

+0

なぜ変数宣言の整数型を定義するのが望ましいのですか? – myDoggyWritesCode

+0

私が正しく理解しているか確認してください。また、それは私の質問の最後に書いたことを説明するでしょう。はい、最適化コンパイラは変数xと値10を格納しません。この場合、実行時関与は存在しないからです。しかし、私が論理計算/ローカルストレージから引数を得ている私の場合のように実行時関与が存在する場合、関数を介してそれらを取得することは良いことです。関数を介して、私はあなたの方法のconst std :: string&str()または私の方法2を意味します。正しいですか?もしそうなら、私のファイルのほとんどの変数は実行時ロジックを必要とするので、方法2の方が良いと思います。 – myDoggyWritesCode

+1

@ user3241111整数変数をソースファイルに格納すると、メモリの容量が少なくて済むだけでなく、コンパイラによる最適化の妨げにもなります。たとえば、積分が後にループカウントとして使用されるとします。コンパイラがヘッダーでそれを見て、それが小さいと見たら、効果的にループを展開することができるかもしれません。しかし、宣言するだけでソースファイルに定義すれば、コンパイラはそれを行うことができません。あなたの2番目のコメントには、答えははいです。重要なことは、グローバル変数と名前空間のスコープ変数を後で使用するかどうかにかかわらず、初期化する必要があることを覚えておくことです。 –

関連する問題