2017-10-08 165 views
2

在他的著作「編程,原理和用C++的做法」 Bjarne的Stroustrup的介紹對314-316頁(第9.4.4)成員初始化列表概念。他用下面的例子:使用成員初始化列表會使初始化稍微快一點嗎?

// 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; 
}; 

在315頁,他說:

我們可以這樣寫:

Date::Date(int yy, int mm, int dd) // constructor 
{ 
    y = yy; 
    m = mm; 
    d = dd; 
} 

但我們會在原則上首先必須默認初始化成員然後爲它們分配值。

因此,我可以得出結論:使用成員初始化列表使代碼稍微快一點?當然,沒有人會注意到現代個人電腦。但是我打算使用C++進行嵌入式開發。

編輯:
我會進一步說明我的問題。實際上,「略快」我的意思是「所涉及的CPU週期較少」。
我也同意了這個特殊的例子潛在效率增長將接近落空。但是對於更大的類和結構,它可能會在微控制器上變得明顯。

+4

使用'int's?沒有任何區別。嘗試一些沉重的課程。 – DeiDei

+0

如果沒有副作用,則全部優化。 –

+0

使一個成員爲const。現在哪種方式可行?這些決定涉及的性能不止於此。始終使用成員初始化程序列表作爲默認值。 – StoryTeller

回答

5

在第二個示例中,您未初始化,您正在分配已經初始化的變量。在進入構造函數之前,變量被初始化(默認構造),所以你實際上設置了它們兩次。

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)); 
} 

這將打印

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

所以你看,他們絕對不當量。事實上,例如,您無法在構造函數中指定const字段

+0

Waw,有趣的代碼片段!所以在你的例子中:(1)「在構造函數中賦值」導致對Foo構造函數的3次調用,以及(2)「在初始化符列表中賦值」只導致1次調用Foo構造函數。 –

+0

這3個調用Foo的構造函數=>這意味着有3個Foo對象坐在內存中的某處? –

+1

實際上,對於'Foo'構造函數和一個複製賦值運算符的兩次調用,構造'Bar'時調用'Foo()'。然後調用'Foo(int)'來構造一個臨時'Foo',它通過const引用傳遞給'Bar'中包含的'foo'的'operator =',它複製該值。然後臨時銷燬。成員初始化列表避免了這種情況,因爲它是一個限制對象的初始化對象,因此編譯器可以自由地執行任何他想做的事情。它們不僅僅是一段代碼中的賦值,就像在構造函數中一樣。 – Jack

1

C++標準規定 「缺省初始化」,如下所示:

[dcl.init]

爲默認初始化類型T的對象是指:

- 如果T是 (如果T沒有缺省構造函數或重載分辨率爲 (1)(可能爲cv-qualified)類類型(第9章),則調用T的默認 構造函數(12.1)(並且初始化爲 ) 3.3)導致的模糊或在被刪除的功能或 從初始化的上下文中)不可訪問的;

- 如果T是 數組類型,每個元素是缺省初始化;

- 否則,不進行初始化。

你的班級成員是普通的,花園式的,int s。他們不是班級。他們不是陣列。因此,在int的情況下,默認初始化不執行任何操作。

我希望大多數編譯器能夠在你的兩個例子中生成相同的代碼。無論如何,這沒有任何區別。

+0

謝謝@SamVarshavchik。你能想到一個重要的例子嗎? –

+0

這是從標準的引用中指出的。如果類成員本身是一個(另一個)類,並且構造函數實際上做了某件事,那麼它就很重要。 –

+0

謝謝@SamVarshavchik :-) –

相關問題