2017-10-08 7 views
2

彼の著書「プログラミング、原則とC++を使った実践」では、Bjarne Stroustrupがメンバ初期化リストを314-316ページ(§9.4.4)に導入しました。彼は次の例を使用しています:315ページメンバ初期化子リストを使用すると初期化が少し速くなりますか?

// Simple Date (year, month, day) 

class Date 
{ 
public: 
    Date(int yy, int mm, int dd): y{yy}, m{mm}, d{dd} 
    { 
     //... 
    } 

private: 
    int y, m, d; 
}; 

を彼は言う:

我々が書かれている可能性:

Date::Date(int yy, int mm, int dd) // constructor 
{ 
    y = yy; 
    m = mm; 
    d = dd; 
} 
をしかし、我々は、原理的には最初のデフォルトメンバーを初期化しているだろうし、次にそれらに値を割り当てます。

したがって、私はメンバー初期化子リストを使用すると、コードが若干速くなりますと結論づけることができますか?もちろん、現代のPCで誰も気付かないだろう。しかし、私は組み込み開発のためにC++を使うつもりです。

編集:
さらに質問を指定します。 「わずかに速い」とは、実際には「CPUサイクルの低減」を意味します。
私は、この特定の例の潜在的な効率の上昇が何にも近くないことに同意します。しかし、はるかに大きなクラスや構造体に対しては、マイクロコントローラ上で目立つようになるかもしれません。次のように

+4

'int's?違いはありません。重いクラスで試してみてください。 – DeiDei

+0

これは、副作用がなければすべて最適化されています。 –

+0

メンバーをconstにする。どちらの方法が現在実行可能ですか?これらの決定にはパフォーマンス以上のものがあります。メンバー初期化子リストを常にデフォルトとして使用します。 – StoryTeller

答えて

5

初期化していない2番目の例では、すでに初期化されている変数に割り当てています。変数はコンストラクタに入る前に初期化され(デフォルトで構築される)、実際には2回設定されます。

あなたはこれが

Assigned in constructor 
Foo(int) 
Foo() 
Foo::operator=(const Foo&) 
Assigned in initializer list 
Foo(int) 

ので、あなたは、彼らは間違いじゃない参照を印刷しas in

#include <iostream> 
using namespace std; 

class Foo 
{ 
    int x; 

public: 
    Foo() : x(0) { cout << "Foo()" << endl; } 
    Foo(int x) : x(x) { cout << "Foo(int)" << endl; } 
    Foo& operator=(const Foo& o) { 
    cout << "Foo::operator=(const Foo&)" << endl; 
    this->x = o.x; return *this; 
    } 
}; 

class Bar 
{ 
    Foo foo; 
public: 
    Bar(const Foo& foo) { this->foo = foo; } 
    Bar(bool, const Foo& foo) : foo(foo) { } 
}; 

int main() { 
    cout << "Assigned in constructor" << endl; 
    Bar bar = Bar(Foo(5)); 
    cout << "Assigned in initializer list" << endl; 
    Bar bar2 = Bar(false, Foo(5)); 
} 

に気づくが、異なるコードをしようとしないようにintは、任意の特定のデフォルト初期化子を持っていません同等。例えば、コンストラクタ内にconstフィールドを代入することはできません。

+0

Waw、興味深いコードスニペット!したがって、あなたの例では、(1) "Assigned in constructor"はFooコンストラクタへの呼び出しを3回、(2) "Assigned in initializer list"はFooコンストラクタへの呼び出しを1回だけにします。 –

+0

Fooコンストラクタへの3回の呼び出し=>これは、メモリ内のどこかに3つのFooオブジェクトがあることを意味します。 –

+1

実際に 'Foo'コンストラクタとコピー代入演算子の2つの呼び出しに対して、' Bar'が構築されるときに 'Foo()'が呼び出されます。そして、 'Foo(int)'は一時的な 'Foo'を構築するために呼び出され、値をコピーする' Bar'に含まれる 'foo'の' operator = 'へのconst参照によって渡されます。その後、一時的なものが破壊されます。メンバの初期化子リストは、オブジェクトを初期化する制限された場所であるため、コンパイラが自由に自由に操作できるため、これを避けることができます。それらはコンストラクタのようにコードブロック内の単なる割り当てではありません。 – Jack

1

C++標準では、 "デフォルトの初期化" を指定:

[dcl.init]

デフォルト初期化するためにT型のオブジェクトを意味する:

- Tは ある場合Tにデフォルトのコンストラクタまたは過負荷の解決がない場合は、 コンストラクタ(12.1)が呼び出されます(初期化は、 になります) (1 3.3)は、あいまいさ、または削除された関数、または が初期化のコンテキストからアクセスできない場合に発生します。

- Tが の配列型の場合、各要素はデフォルトで初期化されます。

- それ以外の場合、初期化は実行されません。

あなたのクラスのメンバーは、平原、庭園の種類、intです。彼らはクラスではありません。それらは配列ではありません。したがって、デフォルトの初期化(intの場合)は何もしません。

ほとんどのコンパイラでは、両方の例で同じコードを生成することが期待されます。それは何の違いもありません。

+0

ありがとうございます@SamVarshavchik。あなたはそれが重要な事例を考えてもらえますか? –

+0

これは標準からの引用によって指摘されています。クラスメンバ自体が(別の)クラスであり、実際には何かを行うコンストラクタを使用する場合、それは重要です。 –

+0

ありがとうございます@SamVarshavchik :-) –

関連する問題