C++中類的構造函數,成員變數是在初始化列表初始化還是在函數體中進行賦值?

class A
{
private:
int a;
std::string s;
public:
A(const int _a, std::string _s);
};
A::A(const int _a, std::string _s)
{
a = _a;
s = _s;
}
class B
{
private:
int a;
std::string s;
public:
B(const int _a, std::string _s);
};
B::B(const int _a, std::string _s) :a(_a), s(_s) {}

這兩種方式,哪種效率更好?時間和空間上更優?


根據stackoverflow上的回答,(c++ - Initializing fields in constructor)

如果你的成員是POD類型(Plain Old Data),那麼list initialization和constructor initialization沒有任何區別,也就是說,

struct A
{
int a;
double b;
A() : a(0), b(0.0) {}
A(int a_in, double b_in) : a(a_in), b(b_in) {}
~A() {}
};

// Equivalent version
struct B
{
int a;
double b;
B() { a = 0; b = 0.0; }
B(int a_in, double b_in) { a = a_in; b = b_in; }
~B() {}
};

以上代碼是等價的。

然而,如果成員變數的類型是非POD類型,比如自定義類型,那麼list initialization的代碼會變成

struct Member1
{
int val;
// Will not compile if un-commenting the line below
// Member1() = delete;

Member1(int a) : val(a) {}
};

struct Member2
{
double val;
// Will not compile if un-commenting the line below
// Member2() = delete;

Member2(double b) : val(b) {}
};

struct A
{
Member1 m1;
Member2 m2;

A() : m1(), m2() {}
A(int a, double b)
{
m1 = a;
m2 = b;
}
/* Equivalent version:
* A(int a, double b) : m1(), m2() { m1 = a; m2 = b; }
*/
};

所以在A(int a, double b)這個構造函數里等於是做了更多的工作:先default construct m1和m2,然後再做m1和m2的copy initialization。

先寫到這裡,有錯再改。


Effective C++里有提到,看過的都知道,初始化列表效率&>=在函數體里賦值。

但有一點要特別注意,成員變數初始化的順序取決於聲明的順序,而不是在初始化列表中的順序。vc不說啥,gcc會報warning。如果遇到初始化有依賴關係的,要特別注意。


A叫賦值

B叫初始化

當你的成員變數是引用的時候,A還可以嗎?


gcc -S,一切都明白了。下面這種方式編譯器可以把實例優化為data,就是程序裡面有初始化變數的數據段,就是不需要初始化,程序載入就初始化好了。上面這種如果編譯器不夠智能,是通過一個函數來初始化的,那麼效率低。

class A a;

class B b;

a可能放bss段(沒有初始化數據的段),b可能放在data段(有初始化數據的段)。

當然要看編譯器,gcc -O2 -S跟gcc -S

可能結果都不一樣


構造列表實際編譯之後會轉換成一段代碼插入你寫的構造函數中,是你寫的代碼前面哦 , 而且是按照成員變數的聲明順序進行初始化。這麼說 ,你就能明白 為啥內置的類型在哪裡初始化效率差的不太多,如果你自己寫的類放在構造函數裡面的初始化的話,會默認調用構造函數和拷貝構造函數,編譯器會先於你的構造代碼調用構造函數構造出這個變數,然後你寫在構造函數中的估計是拷貝構造,或者是賦值構造。寫在構造列表裡面只會調用構造函數!效率差異由此可見!


C part of Cpp部分(內置類型),和純Cpp部分(自定義類型)有效率區別,effective的 條款4說到了


先在在構造函數初始化列表對數據成員進行初始化,然後設置vptr指針(如果需要),最後在構造函數大括弧內,對數據成員進行賦值。


上了2年知乎,頭一次被人邀請,我也能裝b的說一句

歇~邀!

然而這題我不會啊。。。

我不是程序員啊

建議可以看這個網站 知加 - 書中自有黃金屋 尋找答案


推薦閱讀:

cout << sizeof(vector<int>);輸出是32,為什麼?
如何用 VS 2013 打包 VC++ 程序?
設計C++函數傳參時如何決定使用指針還是引用?
C++的編譯單元要知道所有的實現?
switch語句中,case的後面為什麼必須是常量?

TAG:編程語言 | C | 程序優化 |