22

あるフォームを使用する場合と他のフォームを使用する場合の違いを理解したいと思います (ある場合)。

コード 1 (変数で直接初期化):

#include <iostream>

using namespace std;

class Test 
{
public:
    Test() {
        cout<< count;
    }

    ~Test();

private:
    int count=10;
};

int main()
{
    Test* test = new Test();
}

コード 2 (コンストラクターの初期化リストを使用した初期化):

#include <iostream>

using namespace std;

class Test 
{
public:
    Test() : count(10) {
        cout<< count;
    }

    ~Test();

private:
    int count;
};

int main()
{
    Test* test = new Test();
}

セマンティクスに違いはありますか、それとも単なる構文ですか?

4

5 に答える 5

13

メンバーの初期化

どちらの場合も、メンバーの初期化について話しています。メンバーは、クラスで宣言された順序で初期化されることに注意してください。

コード 2: メンバー初期化子リスト

2 番目のバージョンでは:

Test() : count(10) {

: count(10) コンストラクター初期化子 ( ctor-initializer ) でcount(10)あり、メンバー初期化子リストの一部としてのメンバー初期化子です。私はこれを初期化が行われる「実際の」または主要な方法と考えたいのですが、初期化の順序を決定するものではありません。

コード 1: デフォルトのメンバー初期化子

最初のバージョンでは:

private:
    int count=10;

countデフォルトのメンバー initializerがあります。これはフォールバック オプションです。コンストラクターに存在しない場合はメンバー初期化子として使用されますが、クラスでは初期化のためのメンバーのシーケンスが決定されます。

セクション12.6.2 Initializing bases and members, item 10 of the standard:

特定の非静的データ メンバーにブレースまたは等号初期化子と mem-初期化子の両方がある場合、mem-initializer によって指定された初期化が実行され、非静的データ メンバーのブレースまたは等号初期化子が実行されます。無視されます。【例:与えられた

struct A {
int i = / some integer expression with side effects / ;
A(int arg) : i(arg) { }
// ...
};

A(int) コンストラクターは単に i を arg の値に初期化し、i のブレースまたはイコイニシャライザーの副作用は発生しません。—終わりの例]

非静的データ メンバー初期化子を導入すると、構造体は C++11 では集合体と見なされなくなりますが、これはC++14 用に更新されています。


違い

あるフォームではなく他のフォームを使用することの違いは何ですか (もしあれば)。

  • 違いは、2 つのオプションに与えられる優先順位です。直接指定されたコンストラクタ初期化子が優先されます。どちらの場合も、異なるパスを介してメンバー初期化子になります。
  • デフォルトのメンバー初期化子を使用するのが最善です。
    • 次に、コンパイラはその情報を使用してコンストラクタの初期化子リストを生成し、最適化できる可能性があります。
    • すべてのデフォルトを 1 か所で順番に見ることができます。
    • 重複を減らします。その後、手動で指定されたメンバー初期化子リストに例外を入れることしかできませんでした。
于 2016-04-13T14:16:27.520 に答える
5

私が考えることができる違いは、メンバー初期化子リストがデフォルトのメンバー初期化子の前にあるということです。

メンバー初期化子リストでメンバーが省略されている場合に使用される、メンバー宣言に含まれる単純なブレースまたはイコール初期化子であるデフォルトのメンバー初期化子を使用します。

メンバーに既定のメンバー初期化子があり、コンストラクターのメンバー初期化リストにも表示される場合、既定のメンバー初期化子は無視されます。

例えば:

class Test 
{
public:
    Test() {}  // count will be 10 since it's omitted in the member initializer list
    Test(int c) : count(c) {} // count's value will be c, the default member initializer is ignored. 
private:
    int count = 10;
};
于 2016-04-13T13:59:47.547 に答える
1

メンバーの宣言の次に初期化する場合、これは C++11 以降でのみ有効であるため、C++98/03 を使用している場合は、これを完全に行うことはできません。

値が決して変わらない場合は、代わりにこれを a にすることを選択できますconstexpr static。コンパイラは、値に余分なストレージを使用せず (定義しない限り)、値がどこにあっても定数伝播を即座に使用する必要があります。代わりに使用されます。

by-declaration 構文を使用することの 1 つの欠点は、ヘッダー内になければならないことです。これにより、値を変更するたびに、ヘッダーを含むすべての翻訳単位が再コンパイルされます。これに時間がかかる場合は、受け入れられない可能性があります。

もう1つの違いは、メンバー初期化リストを使用すると各コンストラクターの値を変更できるのに対し、宣言によるバージョンを使用すると、すべてのコンストラクターに1つの値しか指定できないことです(ただし、この値を上書きすることはできます...しかし、私は個人的にかなり混乱する可能性があるため、これは避けてください!)。


余談ですがnew、 のインスタンスを作成するために here を使用する必要はありませんTest。これは、人々が他の言語からその言語に来たときによくある間違いです。もちろん、あなたの例の外でこれを行うための多くの用途があります。

于 2016-04-13T13:43:32.780 に答える