14

私が読んでテストしているすべてのことから、(プリプロセッサマクロなしで)共有ヘッダーに定数を定義し、各TUがその定数用に独自のストレージを作成していないことを確認する方法はありません。

私がすることができます:

const int maxtt=888888;

これはまったく同じです:

static const int maxtt=888888;

また、このヘッダーが共有されている場合は機能しますが、各TUは独自ののコピーを取得しますmaxtt。それを防ぐために、これを行うこともできます:

extern const int maxtt;

maxttしかし、ここで定義することはできません。これは、リンカーエラーを回避するためにCPPで実行する必要があります。

私の理解は正しいですか?

4

5 に答える 5

17

変数は一定であるため、各TUが独自のコピーを取得するという事実は通常は関係ありません。

C ++では、名前空間スコープの定数はstaticこの理由で暗黙的に使用されます。多くの場合、これにより、外部リンケージを持つ単一のインスタンスしかない場合よりも優れたコードが可能になります。これは、(変数が実際に定数式である場合)定数を使用サイトに直接折りたたむことができ、まったく保存する必要がないためです。 。

したがって、定数のアドレスなどを実際に取得する必要がない限り、静的バージョンを使用する必要があります。(そして、すでに観察したように、追加することで外部リンケージを強制できますextern。)別の理由は、動的に初期化していて、初期化子を1回だけ呼び出すことである可能性があります。

// header:
extern int const n;

// one implementation:
int const n = init_function_with_side_effects();

(ヘッダー内の)静的構造int const n = init();により、関数はTUごとに1回呼び出されます。

于 2013-01-20T23:00:29.443 に答える
9

あなたが書く、

「私が読んでテストしているすべてのことから、(プリプロセッサマクロなしで)共有ヘッダーに定数を定義し、各TUがその定数用に独自のストレージを作成していないことを確認する方法はありません。」

幸い、それは正しくありません。

小さな整数値の場合は、いつでも。を使用できますenum。トレードオフは、値のアドレスがないため、値のアドレスを渡すことができないことですenum。それは純粋な価値です。

ただし、整数値のためにスペースを節約することは、非常に小さいため、実行するのはかなり無意味です。

それで、大きなことを考えてみましょう、

struct BiggyThingy
{
    unsigned char zeroes[1000000];
    BiggyThingy(): zeroes() {}
};

BiggyThingyでは、ヘッダーファイルで定数を宣言し、プログラム全体で1つの定数を確保するにはどうすればよいでしょうか。

インライン関数を使用します。

最も単純なのはこれです:

inline BiggyThingy const& getBiggyThingy()
{
    static BiggyThingy const theThingy;
    return theThingy;
}

static BiggyThingy const& biggyThingy = getBiggyThingy();

各変換単位で(ポインターのように)参照がスペースを占有することを望まない場合は、表記を簡略化する参照なしで関数を使用してください。

テンプレート定数トリックを使用します。

代わりにテンプレートの特別なルールを利用して、定数を提供する別の方法を次に示します。

template< class Dummy >
class BiggyThingyConstant_
{
public:
    static BiggyThingy const value;
};

template< class Dummy >
BiggyThingy const BiggyThingyConstant_<Dummy>::value;

typedef BiggyThingyConstant_<void> BiggyThingyConstant;

次のようにアクセスできます

foo( BiggyThingyConstant::value )

または、より適切な表記が必要な場合は、インライン関数ソリューションの場合と同様に、翻訳単位ごとに参照を追加できます。

免責事項:

コンパイラによって変更されていないコード。

しかし、あなたはアイデアを得ると思います。;-)

于 2013-01-20T23:30:32.640 に答える
6

このコードは、定数のアドレスを必要とする操作を適用した場合にのみ、TUに定数を生成します。

static int maxtt = 888888;
int * pmaxtt = &maxtt; //address of constant requested.

これも機能し、リンカーの問題を回避できます(ただしmaxtt、アドレスが要求された場合は各TUに格納されます)。

constexpr int maxtt = 888888;

extern最適化できないため、構造は避けてください。

于 2013-01-20T23:00:15.763 に答える
4

ストレージについて非常に心配している場合は、列挙型を使用してください。

enum { maxtt = 888888 };

列挙子はスカラー右辺値であるため、ストレージを必要としません。言うのは違法&maxttです。

于 2013-01-20T23:06:01.183 に答える
0

確かに、セマンティクスの理解は正しいです。

実際には、各変換ユニットは整数のストレージのコピーを取得しない場合があります。理由の1つは、コンパイラーが値を参照する場所にリテラルとして実装する可能性があることです。リンカは、参照されていないことがわかった場合にストレージを破棄するのに十分なほど賢い場合もあります。

コンパイラは、定数にリテラルを自由に使用できない場合があります。その整数への参照を取得するか、その整数へのポインタを取得する場合があります。その場合、ストレージが必要になります。さらに、コンピランド間の独自性も必要になる場合があります。各コンパイルユニットでシンボルのアドレスをconst取得すると、各オブジェクトが一意の静的コピーを取得するため、シンボルのアドレスが異なる場合があります。

列挙型を使用する場合にも、同様の問題が発生する可能性があります。あなたconst intにはストレージがあり、あなたはそのストレージのアドレスを取ることができます。列挙型のアドレスは、どこかに保存するまで取得できません。

于 2013-01-20T23:05:38.850 に答える