C++11 {} 初始化

  • 簡介

    • 說明

      • 主要內容是介紹{},即braces花括號在C++11中的作用。

    • 作用

      • 默認構造和默認初始化.
      • 值列表初始化。{}表示無參默認構造.
    • 默認值和隨機

      #include <iostream>
      
      int main() {
         int a;
         int b{};
         std::cout << a << std::endl;
         std::cout << b << std::endl;
         return 0;
      }
      
      • 隨機值和默認值.

      16
      0
      [Finished in 432ms]
      
    • 結構體

      #include <iostream>
      
      struct T {
         char a;
         char b;
         char c;
         char d;
      };
      
      int main() {
         T a;
         T b{};
         std::cout << std::hex << *(int*)&a << std::endl;
         std::cout << std::hex << *(int*)&b << std::endl;
         return 0;
      }
      
      • 輸出都爲0

      0
      0
      [Finished in 436ms]
      
      #include <iostream>
      
      typedef char (*T)[4];
      
      int main() {
         T a;
         T b{};
         std::cout << std::hex << *(int*)&a << std::endl;
         std::cout << std::hex << *(int*)&b << std::endl;
         return 0;
      }
      
      • 輸出

      10
      0
      [Finished in 429ms]
      
      • 隨機值和默認值0.

    • 重載

      #include <iostream>
      #include <vector>
      #include <initializer_list>
      
      struct T {
         T(){
             std::cout << "default" << std::endl;
         }
         T(std::initializer_list<int> initial) {
             std::cout << "initializer_list" << std::endl;
             std::vector<int> temp{initial};
         }
      };
      
      int main() {
         T a;
         T b{};
         T c{1,2,3};
         return 0;
      }
      
      • 輸出

      default
      default
      initializer_list
      [Finished in 469ms]
      
    • 匹配規則

      • 優先匹配std::initializer_list構造,無參的({})纔可以.

      • 無法構造initializer_list則參數拆分,匹配成員構造.

      • 對成員變量進行構造.

    • 成員變量構造

      #include <iostream>
      
      class T {
      public:
         char s[4];
      };
      
      int main() {
         T a{1,2,3,4};
         std::cout << std::hex << *(int*)&a << std::endl;
         return 0;
      }
      
      4030201
      [Finished in 432ms]
      
    • 數組和成員

      #include <iostream>
      
      class T {
      public:
         char a:4;
         char b:4;
         char s[3];
      };
      
      int main() {
         T a{1,2,3,4};
         T b{1,2,3,4,5};
         std::cout << std::hex << *(int*)&a << std::endl;
         std::cout << std::hex << *(int*)&b << std::endl;
         return 0;
      }
      
      40321
      5040321
      [Finished in 432ms]
      
  • 初始化

    • 各種初始化

      int main() {
         int a(0);
         int b = 0;
         int c{ 0 };
         int d = { 0 };
      }
      
      • 效果都一樣,都是初始化變量.

    • 對等

      int main() {
         int b = { 0 };
         int c{ 0 };
      }
      
      • 兩種相等,後面介紹都統一用不包括=的.

  • 賦值和初始化

    • 初始化和賦值

      #include <iostream>
      
      class T {
      public:
         T(char a) { std::cout << "int" << std::endl; }
         explicit T(T*) { std::cout << "float" << std::endl; }
         T(const T&) { std::cout << "cons" << std::endl; }
         void operator=(const T&) {
             std::cout << "assign" << std::endl;
         }
      };
      
      int main() {
         T a = 1;
         //T b = nullptr;
         T c(nullptr);
         T d = a;
         d = a;
      }
      
      • 執行結果是

      int
      float
      cons
      assign
      
      D:\codes\vs\test\test\x64\Debug\test.exe (進程 9996)已退出,代碼爲 0。
      要在調試停止時自動關閉控制檯,請啓用“工具”->“選項”->“調試”->“調試停止時自動關閉控制檯”。
      按任意鍵關閉此窗口. . .
      
      • 創建時隱式轉換爲對應的構造函數的入參.explicit,不允許隱式轉換.

      • nullptr匹配了T*,註釋掉的代碼因爲構造函數聲明爲explicit所以報錯.

      • 兩個T d=a也被隱式的轉化爲調用構造,而下面的是賦值,則調用賦值運算函數.

    • 小結

      • 聲明時賦值是構造,其他則賦值.

  • {}

    • 轉換一下

      #include <iostream>
      
      class T {
      public:
         T(char a) { std::cout << "int" << std::endl; }
         explicit T(T*) { std::cout << "float" << std::endl; }
         T(const T&) { std::cout << "cons" << std::endl; }
         void operator=(const T&) {
             std::cout << "assign" << std::endl;
         }
      };
      
      int main() {
         T a{ 1 };
         T b{ nullptr };
         T c{(nullptr)};
         T d{ a };
         d = { a };
         //d = { 1, a };
         d = (a);
         d = (1, a);
      }
      
      • 也是隱式轉換,略有差異.

      int
      float
      float
      cons
      assign
      assign
      assign
      
      D:\codes\vs\test\test\x64\Debug\test.exe (進程 9400)已退出,代碼爲 0。
      要在調試停止時自動關閉控制檯,請啓用“工具”->“選項”->“調試”->“調試停止時自動關閉控制檯”。
      按任意鍵關閉此窗口. .
      
      • 也會隱式轉換.不容易出錯.

  • 出錯

    • 函數還是構造

      int main() {
         int a();
         a = 2;
         return 0;
      }
      
      • 無參就是函數聲明.

    • 窄化

      int main() {
         int a{1.0};
         return 0;
      }
      
      • 編譯報錯,因爲會窄化,即double->int丟失數據.

    • 窄化概念

      • 基本類型之間,賦值導致了數據可能丟失.
    • 窄化二

      int main() {
         char a{1l};
         char b{127l};
         char c{128l};
         return 0;
      }
      
      • 這裏前兩個都不會,但是128超過了signed char的存儲範圍.

      • 上面的浮點不能往非浮點類型轉換.

  • 總結

    • 匹配優先級:initializer_list,構造,成員.

    • 作用: 統一初始化方式,適用性廣.

    • 注意: 默認初始化的行爲差異,auto的影響,空initializer_list:({}).

  • 發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章