21

Effective C++ (第3 版)、項目 2 (Preferおよびto )constでは、クラス固有の定数のコード セグメントは次のように読み取られます。enuminline#define

class GamePlayer {
private:
    static const int NumTurns = 5;    // constant declaration
    int scores[NumTurns];             // use of constant
    ...
};

この本は、(私自身の言葉で) それstatic const int NumTurns = 5;は、アドレスが決して使用されない静的な整数定数でない限り、クラス メンバーに対して C++ で通常必要とされる定義ではないと述べています。上記が定数に当てはまらない場合、またはコンパイラが何らかの理由で定義を要求する場合は、次のように定義を実装ファイルで提供する必要があります。

const int GamePlayer::NumTurns;    // definition of NumTurns; see
                                   // below for why no value is given

この本によると (私自身の言葉でも)、値は宣言で既に指定されているため、定義には値が指定されていません。

これは、宣言と定義の定義について私がすでに知っていると思っていたことを混乱させています (そして、この質問をする前に Google で再確認しました):

  • static const int NumTurns = 5定義がないのはなぜですか?NumTurnsここの値に初期化されていませ5んし、宣言と定義が一緒になった場合を初期化というのではないでしょうか。
  • なぜstatic整数定数は定義を必要としないのですか?
  • 値が定義されていない場合、2 番目のコード スニペットが定義と見なされるのはなぜですか?
  • 初期化は定義ではありませんか?ここで「唯一の定義」ルールに違反しないのはなぜですか?

この時点で私は自分自身を混乱させている可能性があるので、誰かが親切に私をゼロから再教育できますか: なぜこれらの 2 行のコード宣言と定義が他の行ではなく、初期化のインスタンスがあるのですか? 初期化も定義ですか?

クレジット: コード スニペットは本から直接引用されています。

編集定義と宣言の違いは何ですか?

  • 宣言は、識別子と型を導入します
  • 定義はインスタンス化して実装します

だから、ええ...それはここで起こっていることではないようです.

編集 2 : コンパイラが静的整数定数をメモリ内に格納せず、コード内でインラインに置き換えるだけで最適化できる可能性があると考えています。しかし、NumTurnsアドレスが使用されている場合、インスタンス化が既に存在するため、宣言が宣言 + 定義に自動的に変更されないのはなぜですか?

編集3:(この編集は元の質問とはあまり関係がありませんが、まだ未解決です。以下の各回答のコメントにコピーして貼り付ける必要がないように、ここに配置します。これについて回答してくださいコメントで. ありがとう!)

答えてくれてありがとう。私の頭は今でははるかに明確になりましたが、編集 2 からの最後の質問はまだ残っています: コンパイラが定義が必要なプログラム内の条件を検出した場合 (たとえば、プログラムで使用されている場合)、なぜ自動的に再解釈し&NumTurnsないのですか?static const int NumTurns = 5;宣言のみではなく宣言と定義?プログラム内の他の場所の定義が持つすべての構文があります。

私は学校で Java のバックグラウンドを持っており、上記の方法で静的メンバーに対してこのような個別の定義を作成する必要はありませんでした。C++が違うのはわかっているのですが、上記がどうしてこうなるのか知りたいです。アドレスが使用されていない場合にインラインで置換される静的な整数メンバーは、基本的な機能というよりも最適化のように聞こえますが、なぜそれを回避する必要があるのですか (条件が使用されていない場合に定義として別のステートメントを提供する)元のステートメントの構文で十分であるにもかかわらず満たされる) 逆の方法ではなく (構文が十分であるため、必要なときに元のステートメントを定義として扱うコンパイラー)?

4

3 に答える 3

13

免責事項: 私は標準的な第一人者ではありません。

次の 2 つを読むことをお勧めします。

http://www.stroustrup.com/bs_faq2.html#in-class
および:
定義と宣言の違いは何ですか?

static const int NumTurns = 5 が定義ではないのはなぜですか? ここで NumTurns は値 5 に初期化されていませんか? また、宣言と定義が一緒に発生する場合、初期化と呼ばれるのではないでしょうか?

高レベルでは、定義 (宣言ではなく) はエンティティ (変数、クラス、関数) をインスタンス化または実装します。
変数の場合、定義により変数がプログラム メモリに割り当てられます。
関数の場合 - 定義は、アセンブリ命令にコンパイルできる命令を提供します。*

コード行

static const int NumTurns = 5;

NumTurnsデフォルトではプログラムメモリに割り当てられないため、宣言のみです。プログラム メモリ内にの (唯一の) インスタンスを作成するには、必要な定義NumTurnsを提供する必要があります。

const int MyClass::NumTurns;  

ビャルネの引用:

クラス外の定義がある場合にのみ、静的メンバーのアドレスを取得できます。

class AE {
    // ...
public:
    static const int c6 = 7;
    static const int c7 = 31;
};

const int AE::c7;   // definition

int f()
{
    const int* p1 = &AE::c6;    // error: c6 not an lvalue
    const int* p2 = &AE::c7;    // ok
    // ...
}

なぜ静的整数定数は定義を必要としないのですか?

あなたが彼らのアドレスを取得したい場合、彼らはそうします。

初期化は定義ではありませんか?

いいえ。初期化は、いくつかのエンティティ (プリミティブ、オブジェクト) に初期値を設定する行為です。

void someFunc (){
  int x; //x is declared, but not initialized
  int y = 0; //y is declared+ initialized.
}

ここで「唯一の定義」ルールに違反しないのはなぜですか?

なぜですか?NumTurnsコード全体にまだ1つあります。シンボルMyClas::NumTurnsは 1 回だけ表示されます。この定義では、変数がプログラム メモリに表示されるだけです。ODR 規則では、シンボルは 1 回だけ宣言できると規定されています。

編集: 質問は基本的に「なぜコンパイラが独自に決定できないのですか?」に要約されます。私は委員会のメンバーではないので、完全に正当な回答をすることはできません。
私の賢明な推測では、コンパイラに物事を決定させることは C++ の哲学ではありません。コンパイラーに決定させる場合、例えば静的な整数 const をどこで宣言するか、私は開発者として次の問題を提起する可能性があります。

1) コードがヘッダーのみのライブラリの場合はどうなりますか? コンパイラはどこで変数を宣言する必要がありますか? 遭遇する最初のcppファイルで?main を含むファイルで ?

2) 変数を宣言する場所をコンパイラが決定した場合、この変数が他の静的変数 (手動で宣言したもの) と一緒に宣言され、キャッシュの局所性をタイトに保つという保証はありますか?

「コンパイラを暴走させる」という考え方を承認するとすぐに、ますます多くの質問が提起されます。これは、Java と C++ の根本的な違いだと思います。

Java: JVM にヒューリスティックスを行わせます。
C++: 開発者にプロファイリングを任せます。

最終的に、 C++ では、コンパイラはすべてが理にかなっていることを確認し、コードをバイナリに変換します。開発者の代わりに仕事をするのではありません。

*マネージ C++ を使用する場合はバイトコード (boo...)

于 2016-01-06T10:05:00.983 に答える