C++11における変数初期化方法のまとめ

4897 ワード

1背景
参考資料[1]P 39によると、C++言語では、初期化と付与は同じ概念ではない.
≪初期化|Initialization|oem_src≫:変数の作成時に初期値を付与します.
代入:オブジェクト(作成済み)の現在の値を消去し、新しい値で置き換えます.
参考資料[1]P 39は,初期化は非常に複雑な問題であるため,この問題を専門にまとめる必要があると指摘している.
2リスト初期化
参考資料[1]P 39は、C++11の新しい規格の一部として、変数をカッコで初期化することが全面的に適用されていることを指摘している(これまでは、配列を初期化する際にのみ用いられていた).リストの初期化には、次の2つの形式があります.
int a = {0};  //        1
int a{0};      //        2
は、上記の2つの方法のいずれも変数aを0に初期化することができることを示している.
2.1制限
組み込みタイプのリストを初期化すると、初期値が失われるリスクがある場合、コンパイルは次のようにエラーを報告します.
int a = 3.14;   //   ,         ,        。
int a = {3.14}; //   ,          (  ,g++          ,    )。

g++4.8.4を使用して、上記の2つの初期化方式をそれぞれテストします.前者はエラーなし、警告なしですが、後者は警告を提示します(エラーではありません!):
warning: narrowing conversion of ‘3.1400000000000001e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]

2.2拡張
また、参照資料[1]P 39は、括弧で囲まれた初期値は、変数の初期化だけでなく、オブジェクト(旧変数)に新しい値を付与するためにも使用できることについても言及している.
int a = 1;   //     ,      1
a = {3};     //    a   3

2.3用途
6章のクラスメンバーの初期化やfor()で定義された変数など、変数の初期化が必要な場所で使用できます.
for (int i{0}; i < 10; i++) {
...
}

3コピー初期化
参照資料[1]P 76は、変数を等号で初期化すると、実際にコピー初期化(copy initialization)が実行され、コンパイラは等号の右側の初期値を新しく作成されたオブジェクトにコピーすると指摘している.
string s1;       //           
string s2 = s1;  //      ,s2 s1   

4直接初期化
参考資料[1]P 76は、新しく作成された変数の右側に初期値を括弧で囲み(等号なし)すると、直接初期化(direct initialization):
string s1();        //            
string s2("hi");    //      
string s3(3, 'c');  //      ,s2    ccc

参照資料[1]P 89は、カッコを使用して初期値を提供することは、オブジェクトを構築するために使用されるので、直接初期化とは、対応するコンストラクション関数を明示的に呼び出すことであることが分かる.参考資料[1]P 262は、値初期化の3つのケースをまとめている.
a)                         ;
b)                  ;
c)   T()                (T    )。

参照資料[1]P 265は、explicitコンストラクション関数は直接初期化にのみ使用できることを指摘している.
4.1特例——vector
vectorが直接初期化を使用する場合は、繰り返し回数を指定する必要があります.
vector v1("hello", "world"); //   
vector v2{"hello", "world"}; //   ,       
vector v3(2, "hello");       //   ,              ,  v3    "helloheloo"

カッコを使用していても、直接初期化の役割を果たす場合があります(カッコに相当します):
vector v4{10};      //      ,v4 10        
vector v5{10, "hi"};//      ,v5 10   “hi”   

原則:参考資料[1]P 89は、初期化プロセスは、可能な限りカッコ内の値を要素初期値リストとして処理(リスト初期化)し、リスト初期化が実行できない場合にのみ他の初期化方式を考慮すると指摘している.
5デフォルト初期化
参照資料[1]P 40は、変数を定義する際に初期値が指定されていない場合、変数はデフォルトで初期化され、具体的な値は変数タイプとその位置によって決定されると指摘している.参考資料[1]P 262は、デフォルト初期化が発生した3つのケースをまとめている.
5.1組み込みタイプ
5.1.1ローカル変数
5.1.1.1非staticローカル変数
参照資料[1]P 40は、ポインタを含む関数体内部の内蔵型変数は初期化されないことを指摘している.参照資料[1]P 47は、他の組み込みタイプと同様に、ブロックの役割ドメイン内で定義されたポインタが初期化されていなければ、不確定な値も持つことを指摘している.参考資料[1]P 185で自動オブジェクトを紹介する際にも,この問題を指摘する.
3.1.1.2 staticローカル変数
参考資料[1]P 185では、ローカル変数に明示的な初期化値がない場合、値の初期化(デフォルトの初期化ではありません!)が実行されることを示しています.組み込み型のローカル静的変数は0に初期化されます.
5.1.2グローバル変数
0に初期化します.
5.2種類
参照資料[1]P 236は、クラスがデフォルト構造関数と呼ばれる特殊な構造関数によってデフォルト初期化プロセスを制御することを指摘している.デフォルトのコンストラクション関数には、実パラメータは必要ありません.参照資料[1]P 637はまた、クラスごとに初期化オブジェクトをカスタマイズする方法(デフォルトコンストラクタ)も指摘している.たとえばstd::stringは、ローカルでもグローバルでもデフォルトで空に初期化されます.
string a;                             //           
tuple threeD; //   tuple                  

5.3例外
参考資料[1]P 89は、一部のクラスではデフォルト初期化がサポートされていないため、初期値を明確に提供する必要があると指摘している.参照資料[1]P 236の説明によれば、このようなデフォルトの構造関数はないと推測される.たとえば、次の定義では、コンパイルエラーが発生します.
class Person {
	public:
	Person(string name, string addr):  //           ,   
	name(this->name), addr(this->addr) //    Person        ,
	{}								   //  Person          
									   //     ,  Person    
									   //     !
	private:
	  const string name;
	  const string addr;
};

int main(void)
{
	Person p;
}
g++4.8.4を使用して上記のコードをコンパイルし、ヒント:
test.cpp|36 col 9| error: no matching function for call to ‘Person::Person()’

6値初期化
参考資料[1]P 88は値初期化の例に言及し、vectorオブジェクトが初期値を提供せずに要素の数を収容することを提供し、このとき値初期化の要素初期値が作成され、コンテナ内のすべての要素に付与される.この初期値はvectorオブジェクトの要素のタイプによって決まります.
vector ivec(10);  // 10   ,       0
参考資料[1]P 262は、対象
デフォルトの初期化または
値初期化時に自動実行
既定のコンストラクション関数.
7クラスメンバーの初期化
7.1クラス内の初期値
参考資料[1]P 65は、C++11の新しい標準規定は、クラス内のデータメンバーにクラス内の初期値を提供することができることを指摘している.参考資料[1]P 88では、クラス内の初期値はコピー初期化とリスト初期化しか使用できない(直接初期化はできない).参照資料[1]P 246は、クラス内の初期値を提供する場合、シンボル=またはカッコで表す必要があることを示している.クラス内の初期値が指定されていないメンバーは、デフォルトで初期化されます.
class A {
    int a{0};    //       0
    int b = {1}; //       1
    int c = 2;   //       2
    int d;       //      ,      
    int e(3);    //   :           (     )! 
};

参考資料
[1]C++Primer中国語版(第5版)