2016-01-12 4 views
6

ヘッダーファイルでは、大域定数を宣言して1行に定義することができます。多くの翻訳単位に含まれると、静的定数のオーバーヘッド?

// constants.h 
namespace Constant{ 
    static const unsigned int framerate = 60; 
    static const char * const windowName = "Test"; 
    static const unsigned char * const cursorBitmap = { lots of data }; 
} 

それは私が一つの場所で私の定数を保つことができ、1つのファイルで定数を宣言し、可読性を手伝っ、他でそれを定義する必要が避けられるので、私はこの形式を好みます。ただし、いずれの翻訳単位にもconstants.hが含まれている場合は、これらの定義を単位としてに展開します。

constants.hを多くの翻訳単位に含めると、例えばcursorBitmapなどの配列定数が非常に大きいと私の質問になりますが、 100単位に含めると、私のプログラムには各文字列と配列リテラルの100個のコピーが含まれますか?または、ポインタと値だけがコピーされますか?

オーバーヘッドがある場合は、宣言と定義を分ける必要なく回避できますか?

(また、私は「静的」を推測しているが、この使用法では冗長ですが、私はとにかくそれを置くのが好き)、文字列リテラルは、様々な翻訳単位内で重複しているかどうかは

+2

また、C++ 17ドラフトには 'inline'変数があります。 – Simple

+0

これは**これらの変数を別のファイルに定義する必要はありません**。それらは宣言であり、多くの場合、定義を提供する必要はありませんが、場合によっては定義する必要があります。たとえば、これらの定数のいずれかを参照渡しする関数に渡す場合は、定義が必要です。 –

答えて

3

は、実装の質の問題です。

直接宣言されたオブジェクトは、このヘッダーが含まれる各翻訳単位で複製されます。それはあまりありません。また、ある定数のアドレスが直接的または間接的に使用されていない翻訳単位では、最適化されている可能性があります。

あなたはこのように、あなたはクラステンプレートを使用することができ、唯一の各定数のコピー、あるいはなくてもコピーを確保したい場合:

constants.h
#pragma once 

template< class Dummy > 
struct Constant_{ 
    static const unsigned int framerate; 
    static const char * const windowName; 
    static const unsigned char * const cursorBitmap; 
}; 

template< class Dummy > 
const unsigned int Constant_<Dummy>::framerate = 60; 

template< class Dummy > 
const char * const Constant_<Dummy::windowName = "Test"; 

template< class Dummy > 
const unsigned char * const Constant_<Dummy>::cursorBitmap = ...; 

using Constant = Constant_<void>; 

しかし、それは私見よりますそれは価値があるよりも働きます。

同様の代替案は、定数ごとに1つずつ、inline関数を使用することです。名前空間内staticを用いて第1の

+0

TUは最終的にリンクされたバイナリとどのように関連していますか? "100単位に含めると私のプログラムには各文字列と配列リテラルの100個のコピーが含まれますか?"非静的な場合はどうでしょうか? – xaxxon

+0

@ xaxxon:ライブラリとプログラムは、2つの異なる種類のものです。この質問は、プログラムに関するものです。通常の図書館は、(翻訳された)翻訳単位の集まりであり、単独または一括して使用することができます。そのために重複を避ける方法を考えるのは難しいですが、それでも実装の品質の問題です。 –

+0

@ xaxxon:「非定型」に関しては、おそらく外部リンケージを意味します。上のテンプレート技法は、ヘッダーのみのモジュールと互換性のある外部リンケージ定数を生成します。代わりに、実装ファイル内の定数を定義することですが、OPは、 "あるファイルで定数を宣言し、別のファイルで定数を宣言する必要がなくなります"ということを避けたいと述べました。 –

0

は、C++ 98以降廃止され:

D.2 staticキーワード
名前空間スコープのオブジェクトを宣言するときに廃止されstaticキーワードの使用(3.3参照.5)

次に、constは、C++での内部リンケージを単独で意味します。

第3に、正確な答えは使用するコンパイラとオプションによって異なります。重複は、特にLTO(Link Time Optimization)を使用できる場合は、コンパイラ/リンカによって排除できます。

1

100単位に含めると、プログラムには各文字列と配列リテラルの100個のコピーが含まれますか?または、ポインタと値だけがコピーされますか?

この標準では、文字列リテラルの統合は保証されていないため、実装するまでです。GNU/Linux上のGCC 5.1.1を使った簡単なテストでは、ではないは最適化されていないビルドで統合されていましたが、-Oまたは-Osを使用すると統合されています。しかし、それは実際のchar配列をマージするだけです。コンパイラがポインタや数値定数(ODRが使用されていないか、PODタイプのものではない場合は、翻訳単位にローカルである場合は、 as-ifルール)、しかし、コンパイラはそれらを簡単に統合することができないかもしれません。標準では、異なるオブジェクトであることが要求されているため、異なるアドレスを持つ必要があります。 as-ifルールでは、アドレスを取得する場合でも削除が許可される可能性がありますが、一般的にグローバルなプログラム最適化が必要です(ライブラリを含む)。リンクが最適化されていない可能性があります、および/またはコンパイラとリンカの設定だけに依存します。言い換えれば、それは正しい状況下で起こるかもしれませんが、それは起こりそうにないでしょう。

私自身のテストでは、GCC 5.1.1も-Os -fltoで、const REFによって公開さstatic const unsigned intオブジェクトを統合(サイズを最適化し、リンク時の最適化を可能にする)しないことを示しています。現代的な実装がこの困難であいまいな最適化を実行した場合、私は率直に驚くでしょう。

(また、私は推測している「静」は、この用法では冗長ですが、私はとにかくそれを置くのが好き)

あなたが複数の翻訳単位を持っている場合は、そうでないだろうので、それは冗長ではありません1つの定義ルール(ODR)を実行してください。ただし、名前空間スコープのstaticは構文的には古くなっていると考えられています(代わりにC++ 98で導入された匿名の名前空間の使用を検討してください)。 (。乾杯とHTHに応じて - アルフ)

あなたが唯一の各定数のコピー、あるいはなくてもコピーを確保したい場合は、このように、クラステンプレートを使用することができます。

このような運がありません。スタンダードには、テンプレートにどれくらいのスペースが使われているかについての保証はありません。すべてのテンプレートが保証するのは、潜在的に多くのコピーのうちの1つだけが、as-ifルールの下で使用されるか、または使用されるように見えるということです。実際には、少なくともGCC 5.1.1は実際にはではないので、私のシステムで-Os -fltoであっても、static const unsigned intの冗長性を取り除いてを削除しているので、それはそれよりも悪いです。これは、2つの翻訳単位を使用していることを意味します。unsigned intのイニシャライザ値は、2つの別々の場所にありますが、いずれか1つのみが使用されています(すべてのポインタと参照はこの場所のみを参照します)。

関連する問題