2009-03-31 21 views
6

私はC言語でプログラミングをしてきたがしばらく++と私は両方の方法を使用しました:コンストラクタでの初期化、ベストプラクティス?

class Stuff { 
public: 
    Stuff(int nr) : n(nr) { } 
private: 
    int n; 
} 

それとも

class Stuff { 
public: 
    Stuff(int nr) { 
     n = nr; 
    } 
private: 
    int n; 
} 

注:これは似ていますが、同じではありませんthis、同じではありません。

ベストプラクティスとは何でしょうか?

答えて

21

初期化リストが優先されます。 FAQ 10.6

+2

そのリンクでは禁止されています。私はこれがなぜリンクのみの答えが落ちるのかと思います。 – wvdz

+0

ここに、イニシャライザーリストが推奨される理由を説明する現在のリンクがあります。 https://isocpp.org/wiki/faq/ctors#init-lists – NigoroJr

5

可能であれば、イニシャライザリストを使用してください。 intの場合はどちらも問題ありませんが、より複雑なメンバオブジェクトの場合は、呼び出されるオブジェクトのデフォルトのコンストラクタが終了し、そのオブジェクトに代入されます遅いです。

さらに、デフォルトのコンストラクタを持たないconstメンバーまたはメンバーの場合は、そのようにする必要があります。

+2

また、参照メンバーを使用するにはinitリストが必要です。 –

2

可能であれば、最初のバージョンを使用してください。

最初のものは、初期化子リストを使用して初期化され、実際にはメンバーのコンストラクタが呼び出されます。

2番目は割り当てです。 nがデフォルトのコンストラクタを持つ型であれば、それはすでに呼び出されていて、次にそれに割り当てられます。 nにデフォルトのコンストラクタがない場合は、最初の型を使用する必要があります。同様にnが参照の場合:int &n

あなたのコンストラクタにパラメータの1つを直接取るメンバーのコンストラクタがない場合は、変換を行うことができるプライベートな静的関数を追加する価値があります。

1

私は一般的にできる限り初期化リストを作成しようとします。まず、コンストラクタでコードを初期化していることを明示します。 constメンバをこのように初期化します。

コンストラクタの本体にコードを挿入するだけであれば、後でコンストラクタの "setup"ルーチンに大きなチャンクを移動して後でそれを移動させることができます。

しかし、それは外に取ることができます。私は、2ページのinitilizerコード、コンストラクタコード、および残りのクラスコードの2ページを持つクラスを作成することを好む同僚を持っています。私はそれが本当に読むのは難しいと思う。

0

2番目のオプションは、初期化ではなく割り当てです。ユーザー定義のデフォルトコンストラクタを持つ型では、2番目のオプションはデフォルトのコンストラクタを呼び出し、後で代入演算子(ユーザー定義かどうかに関わらず)を呼び出して値を割り当てます。

デフォルトの初期化はできません:デフォルトのコンストラクタがない属性がある場合は、参照を保持するかどうか(定数かどうか)、定数を持つかどうかを初期化子リストで初期化する必要があります。あなたは括弧内の初期化リストでそれらの価値を初期化することはできませんが、PODのタイプについて

class X { 
public: 
    X() : array() {} // value-initializes the array 
// equivalent to: 
// X() { for (int i = 0; i < 10; ++i) array[i]=0; }  
private: 
    int array[10]; 
}; 

配列はなく、コンストラクタ本体で、値が初期化初期化リストにすることができ

class X { 
public: 
    X() : pod() {} // value-initializes 
// equivalent to (but easier to read and subtly faster as it avoids the copy): 
// X() { pod = {}; } 
private: 
    PODType pod; 
}; 

最後に、一部のクラスでは、デフォルトの構築後により複雑な(達成可能であれば)コンストラクタを使用して機能を提供します。

class X 
{ 
public: 
    X() : v(10) {} // construct a vector of 10 default initialized integers 
// equivalent to: 
// X() { for (int i = 0; i < 10; ++i) v.push_back(0); } 
private: 
    std::vector<int> v; 
}; 

最後に、それらが実際に同等である場合、初期化リストはC++ではより慣用的です。

12

イニシャライザを使用する大きな利点:イニシャライザリストのどこにでも例外がスローされた場合、デストラクタは既に初期化されているメンバーに対してのみ呼び出されます。

コンストラクタ本体を使用してオブジェクトを初期化するときは、例外を適切に処理し、オブジェクトを適切に巻き戻す必要があります。これは、通常、正しいことを得るのがはるかに難しいです。

0

ヘッダー(.h)にイニシャライザーリストを宣言する必要はないと付け加えたいと思います。これはコンストラクタの実装時に行うことができます(これは非常に一般的です)。それでは

//Stuff.h 
class Stuff { 
public: 
    Stuff(int nr); 
private: 
    int n; 
} 

//Stuff.cpp 
Stuff::Stuff(int nr) 
: n(nr) 
{ 
    //initalize complex members 
} 

は合法で、IMO、それは重要なフィールドの初期化を集中します。複雑なメンバーを体内で初期化する必要がある場合があるので、初期化リストと複雑な初期化をすべて.cppファイルに保存する必要があります。

関連する問題