亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++中各種初始化方式示例詳解

2020-05-23 13:45:40
字體:
來源:轉載
供稿:網友

color: #ff0000">前言

本文主要給大家介紹了關于C++初始化方式的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

C++小實驗測試:下面程序中main函數里a.a和b.b的輸出值是多少?

#include <iostream>struct foo{ foo() = default; int a;};struct bar{ bar(); int b;};bar::bar() = default;int main(){ foo a{}; bar b{}; std::cout << a.a << '/t' << b.b;}

答案是a.a是0,b.b是不確定值(不論你是gcc編譯器,還是clang編譯器,或者是微軟的msvc++編譯器)。為什么會這樣?這是因為C++中的初始化已經開始畸形發展了。

接下來,我要探索一下為什么會這樣。在我們知道原因之前,先給出一些初始化的概念:默認初始化,值初始化,零初始化。

T global;    //T是我們的自定義類型,首先零初始化,然后默認初始化void foo(){ T i;  //默認初始化 T j{}; //值初始化(C++11) T k = T(); //值初始化 T l = T{}; //值初始化(C++11) T m(); //函數聲明 new T; //默認初始化 new T(); //值初始化 new T{}; //值初始化(C++11)}struct A{ T t; A() : t() //t將值初始化 { //構造函數 }};struct B{ T t; B() : t{} //t將值初始化(C++11) { //構造函數 }};struct C{ T t; C()  //t將默認初始化 { //構造函數 }};

上面這些不同形式的初始化方式有點復雜,我會對這些C++11的初始化做一下簡化:

  • 默認初始化 :如果 T 是一個類,那么調用默認構造函數進行初始化;如果是一個數組,每個元素默認初始化,否則不進行初始化,其值未定義。至于 合成的 默認構造函數初始化數據成員的規則是:1.如果類數據成員存在類內初始值,則用該值初始化相應成員(c++11);2.否則,默認初始化數據成員。
  • 值初始化 :如果 T 是一個類,那么類的對象進行默認初始化( 如果T類型的默認構造函數 不是 用戶自定義的,默認初始化之前先進行零初始化 );如果是一個數組,每個元素值初始化,否則進行零初始化。
  • 零初始化 :對于static或者thread_local變量將會在其他類型的初始化之前先初始化。如果T是算數、指針、枚舉類型,將會初始化為0;如果是類類型,基類和數據成員會零初始化;如果是數組,數組元素也零初始化。

看一下上面的例子,如果T是int類型,那么global和那些T類型的使用值初始化形式的變量都會初始化為0(因為int是內置類型,不是類類型,也不是數組,將會零初始化,又因為int是算術類型,如果進行零初始化,則初始值為0)而其他的默認初始化都是未定義值。

回到開頭的例子,現在我們已經有了搞明白這個例子所必要的基礎知識。造成結果不同的根本原因是:foo和bar被它們不同位置的默認構造函數所影響。

foo的構造函數在起初聲明時是要求默認合成,而不是我們自定義提供的,因此它屬于編譯器 合成的 默認構造函數 。而bar的構造函數則不同,它是在定義時被要求合成,因此它屬于我們用戶 自定義的 默認構造函數 。

前面提到的關于值初始化的規則時,有說明到: 如果T類型的默認構造函數不是用戶自定義的,默認初始化之前先進行零初始化 。因為foo的默認構造函數不是我們自定義的,是編譯器合成的,所以在對foo類型的對象進行值初始化時,會先進行一次零初始化,然后再調用默認構造函數,這導致a.a的值被初始化為0,而bar的默認構造函數是用戶自定義的,所以不會進行零初始化,而是直接調用默認構造函數,從而導致b.b的值是未初始化的,因此每次都是隨機值。

這個陷阱迫使我們注意:如果你不想要你的默認構造函數是用戶自定義的,那么必須在類的內部聲明處使用"=default",而不是在類外部定義處使用。

對于類類型來說,用戶提供自定義的默認構造函數有一些額外的“副作用”。比如,對于缺少用戶提供的自定義默認構造函數的類,是無法定義該類的const對象的。示例如下:

class exec{ int i;};const exec e;  //錯誤!缺少用戶自定義默認構造函數,不允許定義const類對象

通過開頭的例子,我們已經對C++的一些初始化方式有了直觀的感受。 C++中的初始化分為6種:零 初始化、 默認初始化、值初始化、直接初始化、拷貝初始化、列表初始化。

零初始化和變量的類型和位置有關系,比如是否static,是否aggregate聚合類型。能進行0初始化的類型的對象的值都是0,比如int為0,double為0.0,指針為nullptr;

現在我們已經了解了幾種初始化的規則,下面則是幾種初始化方式的使用形式:

1. 默認初始化是定義對象時,沒有使用初始化器,也即沒有做任何初始化說明時的行為。典型的:

int i;vector<int> v;

2. 值初始化是定義對象時,要求初始化,但沒有給出初始值的行為。典型的:

int i{};new int();new int{}; //C++11

3. 直接初始化和拷貝初始化主要是相對于我們自定義的對象的初始化而言的,對于內置類型,這兩者沒有區別。對于自定義對象,直接初始化和拷貝初始化區別是直接調用構造函數還是用"="來進行初始化。典型的:

vector<int>  v1(10); //直接初始化,匹配某一構造函數vector<string> v2(10); //直接初始化,匹配某一構造函數vector<int>  v3=v1;  //拷貝初始化,使用=進行初始化

對于書本中給出的示例:

string dots(10, '.'); //直接初始化string s(dots);      //直接初始化

這里s的初始化書本說是直接初始化,看起來似乎像是拷貝初始化,其實的確是直接初始化,因為直接初始化是用參數來直接匹配某一個構造函數,而拷貝構造函數和其他構造函數形成了重載,以至于剛好調用了拷貝構造函數。

事實上,C++語言標準規定復制初始化應該是先調用對應的構造函數創建一個臨時對象,然后拷貝構造函數再將構造的臨時對象拷貝給要創建的對象。例如:

string a = "hello";

上面代碼中,因為“hello"的類型是const char *,所以string類的string(const char *)構造函數會被首先調用,創建一個臨時對象,然后拷貝構造函數將這個臨時對象復制到a。但是標準還規定,為了提高效率,允許編譯器跳過創建臨時對象這一步,直接調用構造函數構造要創建的對象,從而忽略調用拷貝構造函數進行優化,這樣就完全等價于直接初始化了,當然可以使用-fno-elide-constructors選項來禁用優化。

如果我們將string類型的拷貝構造函數定義為private或者定義為delete,那么就無法通過編譯,雖然能夠進行優化省略拷貝構造函數的調用,但是拷貝構造函數在語法上還是要能正常訪問的,這也是為什么C++ primer第五版第13章拷貝控制13.1.1節末尾442頁最后一段話中說:

“即使編譯器略過了拷貝/移動構造函數,但在這個程序點上,拷貝/移動構造函數必須是存在且可訪問的(例如,不能是priviate的)。

拷貝初始化不僅在使用=定義變量時會發生,在以下幾種特殊情況中也會發生:

1.將一個對象作為實參傳遞給一個非引用的形參;

2.從一個返回類型為非引用的函數返回一個對象;

3.用花括號列表初始化一個數組中的元素或一個聚合類中的成員。

其實還有一個情況,比如:當以值拋出或捕獲一個異常時。

另外還有比較讓人迷惑的地方在于vector<string> v2(10),在《C++ Primer 5th》中說這是值初始化的方式,但是仔細看書本,這里的值初始化指的是容器中string元素,也就是說v2本身是直接初始化的,而v2中的10個string元素,由于沒有給出初始值,因此標準庫對容器中的元素采用了值初始化的方式進行初始化。

結合來說:

只要使用了括號(圓括號或花括號)但沒有給出具體初始值,就是值初始化??梢院唵卫斫鉃槔ㄌ柛嬖V編譯器你希望該對象初始化。

沒有使用括號,就是默認初始化??梢院唵卫斫獬桑惴湃尾还?,允許編譯器使用默認行為。通常這是糟糕的行為,除非你真的懂自己在干什么。

4. 列表初始化是C++新標準給出的一種初始化方式,可用于內置類型,也可以用于自定義對象,前者比如數組,后者比如vector。典型的:

int array[5]={1,2,3,4,5};vector<int> v={1,2,3,4,5};

文章寫到這里,讀者認真的看到這里,似乎已經懂了C++的各種初始化規則和方式,下面用幾個例子來檢測一下:

#include <iostream>using namespace std;class Init1{public: int i;};class Init2{public: Init2() = default; int i;};class Init3{public: Init3(); int i;};Init3::Init3() = default;class Init4{public: Init4(); int i;};Init4::Init4(){ //constructor}class Init5{public: Init5(): i{} { } int i;};int main(int argc, char const *argv[]){ Init1 ia1; Init1 ia2{}; cout << "Init1: " << " "   << "i1.i: " << ia1.i << "/t"   << "i2.i: " << ia2.i << "/n"; Init2 ib1; Init2 ib2{}; cout << "Init2: " << " "   << "i1.i: " << ib1.i << "/t"   << "i2.i: " << ib2.i << "/n"; Init3 ic1; Init3 ic2{}; cout << "Init3: " << " "   << "i1.i: " << ic1.i << "/t"   << "i2.i: " << ic2.i << "/n"; Init4 id1; Init4 id2{}; cout << "Init4: " << " "   << "i1.i: " << id1.i << "/t"   << "i2.i: " << id2.i << "/n"; Init5 ie1; Init5 ie2{}; cout << "Init5: " << " "   << "i1.i: " << ie1.i << "/t"   << "i2.i: " << ie2.i << "/n"; return 0;}

試問上面代碼中,main程序中的各個輸出值是多少?先不忙使用編譯器編譯程序,根據之前介紹的知識先推斷一番:

首先,我們需要明白,對于類來說,構造函數是用來負責類對象的初始化的,一個類對象無論如何一定會被初始化。也就是說,當實例化類對象時,一定會調用構造函數,不論構造函數是否真的初始化了數據成員。故而對于沒有定義任何構造函數的自定義類來說,該類的默認構造函數不存在“被需要/不被需要”這回事,它必然會被合成。

  • 對于Init1,由于我們對其沒有做任何構造函數的聲明和定義,因此會合成默認構造函數。
  • 對于Init2,我們在類內部聲明處要求合成默認構造函數,因此也會有合成的默認構造函數。

由于Init1和Init2它們擁有類似的合成默認構造函數,因此它們的ia1.i和ib1.i值相同,應該都是隨機值,而ia2.i和ib2.i被要求值初始化,因此它們的值都是0。

  • 對于Init3,我們在類外部定義處要求編譯器為我們生成默認構造函數,此默認構造函數為用戶自定義的默認構造函數。
  • 對于Init4,我們顯式的定義了用戶自定義默認構造函數。

由于Init3和Init4它們擁有類似的用戶自定義默認構造函數,因此它們的ic1.i和id1.i值相同,應該都是隨機值,而ic2.i和id2.i雖然被要求值初始化,但也是隨機值。

  • 對于Init5,我們顯式的定義了用戶自定義默認構造函數,并且使用了構造函數初始化列表來值初始化數據成員。

由于Init5我們為它顯式提供了默認構造函數,并且手動的初始化了數據成員,因此它的ie1.i和ie2.i都會被初始化為0。

以上是我們的預測,結果會是這樣嗎?遺憾的是,結果不一定是這樣。是我們哪里出錯了?我們并沒有錯誤,上面的程序結果取決于你使用的操作系統、編譯器版本(比如gcc-5.0和gcc-7.0)和發行版(比如gcc和clang)??赡苡械娜四塬@得和推測完全相同的結果,而有的人不能,比如在經常被批不遵守C++標準的微軟VC++編譯器(VS 2017,DEBUG模式)下,結果卻完全吻合(可能是由于微軟開始接納開源和Linux,逐漸的嚴格遵守了語言標準),GCC的結果也是完全符合,而廣受好評的Clang卻部分結果符合。當然,相同的Clang編譯器在Mac和Ubuntu下結果甚至都不一致,GCC在某些時候甚至比Clang還人性化的Warning告知使用了未初始化的數據成員。

雖然,上面程序中有一些地方因為操作系統和編譯器的原因和我們預期的結果不相同,但也有必然相同的地方,比如最后一個使用了構造函數初始化列表的類的行為就符合預期。還有在合成的默認構造函數之前會先零初始化的地方,必然會初始化為0。

至此,我們已經對C++的初始化方式和規則已經有了一個了然于胸的認識,那就是:由于平臺和編譯器的差異,以及對語言標準的遵守程度不同,我們決不能依賴于合成的默認構造函數。這也是為什么C++ Primer中多次強調我們不要依賴合成的默認構造函數,也說明了C++ Primer在關于手動分配動態內存那里告訴我們,對于我們自定義的類類型來說,為什么要求值初始化是沒有意義的。

C++語言設計的一個基本思想是“自由”,對于某些東西它既給出了具體要求,又留出了發揮空間,而那些未加以明確的地方是屬于語言的“灰暗地帶”,我們需要小心翼翼的避過。在對象的初始化這里,推薦的做法是將默認構造函數刪除,由我們用戶自己定義自己的構造函數,并且合理的初始化到每個成員,如果需要保留默認構造函數,一定要對它的行為做到心里有數。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产亚洲精品久久久优势| 日韩中文理论片| 欧美视频在线观看免费| 国产va免费精品高清在线观看| 亚洲人a成www在线影院| yw.139尤物在线精品视频| 色播久久人人爽人人爽人人片视av| 亚洲国产精品热久久| 欧美一区二粉嫩精品国产一线天| 亚洲va久久久噜噜噜| 2019日本中文字幕| 97超碰色婷婷| 精品国偷自产在线视频99| 日韩精品亚洲视频| 77777亚洲午夜久久多人| 日韩大陆欧美高清视频区| 国产精品美女主播在线观看纯欲| 色偷偷av亚洲男人的天堂| 国产在线精品成人一区二区三区| 亚洲国产小视频在线观看| 亚洲精品国产欧美| 国产精品综合不卡av| 久久国产精彩视频| 欧美激情视频在线| 国产精品美女av| 欧美日韩在线观看视频小说| 国产69精品久久久| 美女视频黄免费的亚洲男人天堂| 韩剧1988在线观看免费完整版| 91在线视频导航| 久久影视电视剧免费网站清宫辞电视| 欧美激情免费在线| 久久久精品欧美| 俺去啦;欧美日韩| 国产欧美日韩免费看aⅴ视频| 欧美在线xxx| 久久久久北条麻妃免费看| 亚洲丝袜在线视频| 亚洲丝袜av一区| 国产精品久久久久久亚洲影视| 精品久久久91| 91国在线精品国内播放| 国产精品久久久久久久久影视| 秋霞成人午夜鲁丝一区二区三区| 亚洲欧美日韩区| 亚洲高清色综合| 福利二区91精品bt7086| 最新69国产成人精品视频免费| 欧美专区在线播放| 91久久久久久国产精品| 欧美日韩精品在线| 欧美一级免费视频| 欧美激情2020午夜免费观看| 午夜精品三级视频福利| 日韩精品高清在线观看| 992tv在线成人免费观看| 国产成人极品视频| 欧美裸体xxxxx| 国产热re99久久6国产精品| 国产专区欧美专区| 日韩av电影在线网| 国产成人a亚洲精品| 日韩电影中文字幕在线观看| 国产精品中文字幕在线| 色综合男人天堂| 青青久久av北条麻妃海外网| 亚洲精品999| 国产成人午夜视频网址| 不卡在线观看电视剧完整版| 超碰97人人做人人爱少妇| 日韩一中文字幕| 青青久久av北条麻妃黑人| 国产香蕉精品视频一区二区三区| 国产成人综合一区二区三区| 国产欧美日韩视频| 日韩**中文字幕毛片| 欧美专区日韩视频| 欧美极品少妇xxxxⅹ裸体艺术| 欧美午夜女人视频在线| 国产欧美精品在线| 97成人精品视频在线观看| 狠狠色狠狠色综合日日五| 欧美影院在线播放| 97人洗澡人人免费公开视频碰碰碰| 久久久久久久久中文字幕| 91sao在线观看国产| 欧美成人午夜免费视在线看片| 欧美成人sm免费视频| 91免费欧美精品| 国内揄拍国内精品| 欧美国产日韩xxxxx| 欧美激情在线一区| 日韩极品精品视频免费观看| 欧美精品www| 国产精品自产拍高潮在线观看| 亚洲精品福利在线| 亚洲精品日产aⅴ| 欧美成年人视频网站欧美| 国产97免费视| 91九色视频在线| 国内精品免费午夜毛片| 一区二区三区视频在线| 欧美成人免费全部| 亚洲国产日韩一区| 亚洲精品日产aⅴ| 国产精品成人一区二区三区吃奶| 国产精品老女人视频| 国产美女精品视频免费观看| 亚洲精品国产综合久久| 黑人巨大精品欧美一区免费视频| 色在人av网站天堂精品| 91视频国产高清| 国产视频丨精品|在线观看| 国产精品久久久久久久美男| 国产欧美一区二区三区在线看| 久久免费国产精品1| 国产成人精品免高潮费视频| 欧美一级在线播放| 亚洲成人a级网| 欧美日韩国产页| 久久久久国产精品免费网站| 国产aⅴ夜夜欢一区二区三区| 韩日精品中文字幕| 日韩免费精品视频| 亚洲图片欧美日产| 日韩av在线免费| 91av视频在线| 欧美成年人视频网站欧美| 国产精品久久久久久婷婷天堂| 亚洲欧美国产精品专区久久| 最新91在线视频| 欧美性猛交xxxx偷拍洗澡| 国产精品99蜜臀久久不卡二区| 亚洲一区亚洲二区| 成人精品视频久久久久| 欧美性jizz18性欧美| 日韩欧美高清在线视频| 久久精品国产亚洲7777| 伊人久久综合97精品| 亚洲九九九在线观看| 欧美日韩aaaa| 久久艹在线视频| 97在线视频免费播放| 91免费看国产| 国产精品自产拍在线观| 国产精品第一页在线| 孩xxxx性bbbb欧美| 国产午夜精品理论片a级探花| 欧美最猛黑人xxxx黑人猛叫黄| 亚洲香蕉成视频在线观看| 日韩精品视频在线免费观看| 国产精品一区av| 亚洲精品美女在线观看| 成人h片在线播放免费网站| 国产精品电影久久久久电影网| 在线免费观看羞羞视频一区二区| 国产精品美女www| 91国内产香蕉| 国产va免费精品高清在线| 热re91久久精品国99热蜜臀| 欧美激情在线一区| 亚洲最大福利网| 国产精品欧美日韩一区二区| 亚洲jizzjizz日本少妇|