私の知る限り、C++で変数を初期化する方法は3つあります。
int x = 0; // C-like initialization
int x (0); // Constructor initialization
int x {0}; // Uniform initialization
C++ 11 の均一な初期化が導入され、 C +で異なる構文を必要とするさまざまなタイプの変数を初期化するためのより均一な構文が提供されました+03 。
Cライク、コンストラクタ、統一初期化の違いは何ですか?また、常に統一された初期化を使用する必要がありますか?
まず、ハーブサッターの 次の講演 をご覧になることをお勧めします。ブレース初期化の議論は 23:00頃 から始まります。
プリミティブデータ型の場合、3つすべてで同じ結果が得られます。私は個人的に古いint x = 0
構文を使用することを好みますが、それは個人的な好みに帰着します。
クラス型の場合、ブレースの初期化と古いコンストラクターの初期化は完全に交換可能ではありません。例えば:
vector<int> v (100); // Creates a 100-element vector
vector<int> v {100}; // Creates a 1-element vector, holding the value 100.
これは、std::vector
に、std::initializer_list
を唯一の引数として明示的に定義するコンストラクターがあるためです。それを念頭に置いて
auto var = {1, 2};
var
を識別子としてstd::initializer_list
を作成します。
イニシャライザリストの重要な点は、それらが一貫性を提供するということです。これは、事前に利用可能であったものからの歓迎すべき変更です。たとえば、C++で配列を初期化する場合は、次を使用します。
int arr[] = {1, 2, 3, 4};
ただし、vector<int>
を同じ要素で初期化する場合は、次のいずれかを行う必要があります。
arr
とarr + 4
を渡しますC++ 11では、次のように使用できます
vector<int> v = {1, 2, 3, 4}; // Same syntax. Nice! Note that the = is optional
ブレースの初期化が役立つもう1つの例は、C++の 最も厄介な解析 の回避策を提供することです。話から、2つのクラスOrigin
とextents
があり、それらのインスタンスを渡してrectangle
型の別のオブジェクトを構築できると仮定します。次のステートメント:
rectangle w(Origin(), extents());
rectangle
およびOrigin
temporariesを使用してextents
オブジェクトを作成することはできません。そのステートメントは関数宣言として解析されるためです。 Tsk tsk。したがって、通常は次のようにする必要があります。
Origin o;
extents e;
rectangle w(o, e);
ブレースの初期化を使用すると、その場で作成できます。
rectangle w {Origin(), extents()};
意図したとおりに機能します。つまり、最初の引数がOrigin
オブジェクトで、2番目の引数がextents
オブジェクトでオーバーロードされているコンストラクタに渡されます。
ルールはオブジェクト用です。特別な理由がない限り、ブレースの初期化を使用してください。
Cライク、コンストラクター、および統一初期化の違いは何ですか?
int
のようなプリミティブ型の場合、実用的な違いはありません。代わりに、クラス型T
を考えてみましょう。
最初のスタイルは次と同等です
T x(T(0));
初期化式から一時オブジェクトを作成し、それを移動またはコピーしてx
を初期化します。実際には、移動またはコピーは省略されるため、結果は2番目のスタイルと同じになります。唯一の違いは、アクセス可能なコピーまたは移動コンストラクターがない場合、最初は失敗することです。
2番目は、1つの引数を取るコンストラクターを使用してオブジェクトを直接初期化し、適切なコンストラクターがない場合はエラーを出します。
3番目は、使用可能なコンストラクターによって異なります。
std::initializer_list
を取るコンストラクターがある場合は、それを使用します。また、常に初期化を使用する必要がありますか?
いいえ。場合によっては、initializer_list
コンストラクタと他の引数タイプを取るコンストラクタを区別するために、関数スタイルの初期化が必要になることがあります。例えば:
std::vector<int> v1(10, 42); // 10 elements with value 42
std::vector<int> v2{10, 42}; // 2 elements with values 10 and 42
また、意味のある意味で「均一」ではないため、「均一初期化」と呼ばないでください。正式な用語は「ブレース初期化」です。