1. 程式人生 > 實用技巧 >讀書筆記 《Effective modern C++》之 Moving to Modern C++(二)

讀書筆記 《Effective modern C++》之 Moving to Modern C++(二)

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 q{{1,2,3}}