1. ホーム
  2. c++

[解決済み] c++でオブジェクトを初期化するさまざまな方法

2022-03-04 16:14:31

質問

このクラスを想像してください。

class Entity {
public:
    int x, y;
    
    Entity() : x(0), y(0) { }
    Entity(int x, int y) : x(x), y(y) { }
}

そして、私が知っていると思うものでクラスを初期化する複数の方法を紹介します。

Entity ent1;                //Uses the default constructor, so x=0 and y=0
Entity ent2();              //Uses the default constructor, so x=0 and y=0 (Not sure)
Entity ent3(1, 2);          //Made constructor, so x=1 and y=2
Entity ent4 = Entity();     //Default constructor, so x=0 and y=0
Entity ent5 = Entity(2, 3); //Made constructor, so x=2 and y=3

ヒープメモリ上にオブジェクトを作ることが可能であることは知っていますが、今私が求めているのはそれではないのです。

質問ですが、これらのオブジェクトの初期化方法の違いは何ですか?

いつ、どちらを使うべきか迷っています。

どのように解決するのですか?

Entity ent1;

上記のステートメントは、クラスのデフォルトコンストラクタを使用しています。 Entity .


Entity ent2();

上記の宣言は、もし可能であれば、コンパイラによって関数のプロトタイプとして扱われるでしょう。これは、以下のようなケースとして知られている。 最も厄介なパース (MVP)であり、その存在が「括弧は使わない」という誤解を招く「賢い馬鹿ルール」の出現につながったのです。


このようなステートメントでは、ユーザー定義のコンストラクタが呼び出されます。 ent3 :

Entity ent3(1, 2);

また、MVPが打てるケースはこんな感じです。

Entity ent3_1(int(a), int(b));  // It's not what it looks like.

ent3_1 は変数ではありません。この文は、2つのint型パラメータを持つ関数を宣言しています。 int(a) と同じです。 int a は、C言語とその宣言文の遺産である。


Entity ent4 = Entity();

ent4 適切な のバージョンです。 ent2 C++11までは、デフォルトコンストラクタは値の初期化の一部として呼び出されます。この形式により、曖昧さ解消の原則のために ent2ent3_1 が正しくありません。等号は代入ではありません。 operator= の呼び出しがここで発生します。これは、初期化式をマークアップするための宣言構文の一部です。


Entity ent5 = Entity(2, 3);

ent5 は、ent3 caseのバージョンです。値の初期化の一部として、ユーザー定義のコンストラクタが呼び出されます。


あなたの質問にはC++11というタグが付けられており、C++11では統一された初期化構文が認められています。

Entity ent12{};     // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {};              // Not an assignment
Entity ent15 = Entity{2, 3};    // Not an assignment either!

一様な初期化構文には注意点があることに注意してください。例えば、この行

std::vector<int> v(10); 

は10個の要素からなるベクトルを宣言しています。しかし、この

std::vector<int> v{10};

は、値10を持つint型の単一要素で初期化されたベクトルを宣言しています。このようなことが起こるのは std::vector には、次のようなシグネチャを持つコンストラクタが定義されています。

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

MVPを発生させない()も、望ましくないコンストラクタを呼び出さない{}も使えない場合、値の初期化代入構文で問題を解決できます。

追記:必見 CppCon2018の様子。ニコライ・ヨスッティ "The Nightmare of Initialization in C++"