讀書筆記 《Effective modern C++》之 Moving to Modern C++(二)
阿新 • • 發佈:2020-07-28
Item 7: 區分使用()和{}建立物件
三種常見的建立方式
int x(0); // initializer is in parentheses
int y = 0; // initializer follows "="
int z{ 0 }; // initializer is in braces
但是初始化成員變數有些不一樣
class Widget {
private:
int x{ 0 }; // fine, x's default value is 0
int y = 0; // also fine
int z(0); // error!
};
{}初始化禁止了初始化build-in型別時候的非顯式轉化。此外{}會避免一些因為vexing parse帶來的歧義。
Widget w1(10); // call Widget ctor with argument 10
Widget w2(); // most vexing parse! declares a function
// named w2 that returns a Widget! 函式宣告。
Widget w3{}; // calls Widget ctor with no args
不過{}初始化可能帶來一些意想不到的結果,比如有initializer_list建構函式的情況下。
class Widget { public: Widget(int i, bool b); Widget(int i, double d); Widget(std::initializer_list<long double> il); }; Widget w1(10, true); // uses parens and, calls first ctor Widget w2{10, true}; // uses braces, calls std::initializer_list ctor (10 and true convert to long double) Widget w3(10, 5.0); // uses parens and, calls second ctor Widget w4{10, 5.0}; // uses braces, call std::initializer_list ctor (10 and 5.0 convert to long double)
class Widget { public: Widget(int i, bool b); // as before Widget(int i, double d); // as before Widget(std::initializer_list<long double> il); // as before operator float() const; // convert to float }; // 移動構造和複製構造產生非預期的結果 Widget w5(w4); // uses parens, calls copy ctor Widget w6{w4}; // uses braces, calls std::initializer_list ctor (w4 converts to float, and float converts to long double) Widget w7(std::move(w4)); // uses parens, calls move ctor Widget w8{std::move(w4)}; // uses braces, calls, std::initializer_list ctor (for same reason as w6)
initializer_list建構函式在使用{}初始化被給予很高的優先順序,甚至給與會發生narrow converting的不合法(braced initializer裡被禁止)的initializer_list構造器
class Widget {
public:
Widget(int i, bool b); // as before
Widget(int i, double d); // as before
Widget(std::initializer_list<bool> il);
}; // conversion funcs
Widget w{10, 5.0}; // error! requires narrowing conversions
完全不合法時候才會給到普通的ctor
class Widget {
public:
Widget(int i, bool b); // as before
Widget(int i, double d); // as before
Widget(std::initializer_list<std::string> il); // double或者int沒法隱式轉成string
};
Widget w1(10, true); // uses parens, still calls first ctor
Widget w2{10, true}; // uses braces, now calls first ctor
Widget w3(10, 5.0); // uses parens, still calls second ctor
Widget w4{10, 5.0}; // uses braces, now calls second ctor
空的{}初始化->預設ctor, 而不是一個為空的initializer_list構造器
Widget w2{}; // also calls default ctor
Widget w3(); // most vexing parse! declares a function!
使用為空的initializer_list構造器的正確姿勢(想到了(偽)列表初始化queue,queue