C++類成員默認初始值


有時候我們會不給C++類成員變量賦初始值,或是因為忘記在構造函數中指定(C++11可以寫在類內),或是覺得沒有必要寫。然而,因為覺得編譯器會把變量賦成0而不寫是錯誤的。本文通過C++標准來解釋這個問題。

本文基於N3337(C++11草案)標准。

關於沒有初始化器的對象,在8.5-11中有提及:

If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.

沒有初始化器的對象會被默認初始化;沒有初始化的自動(局部變量)或動態存儲期限(new出來的)對象的值是未定的。

這里涉及到了兩種“無初始化”的概念,沒有初始化器與沒有初始化,注意區分。8.5-6對默認初始化(default-initialize)的定義是:

To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

  • if T is an array type, each element is default-initialized;

  • otherwise, no initialization is performed.

默認初始化T類型的對象是指:

  • 如果T是(可能有constvolatile的)類類型,T的默認構造函數會被調用(如果沒有可用的,初始化就是非法的)(默認構造函數可能會對成員執行默認初始化);

  • 如果T是數組類型,每個元素被默認初始化(同樣是遞歸的默認初始化);

  • 否則,不初始化。

從這些標准中的條款,可以得出結論:自動或動態存儲期限的非類類型對象,無論是否是數組或是否有const修飾,如果不指定初始值,它的值就是未定的。

而整數類型、指針類型等都屬於非類類型,如果我們希望這些類型的成員變量有確定的初始值,即使是看起來默認的0,也要自己寫上初始化

----------------分割線----------------

我在這個問題上栽過大跟頭,這就是我要寫這篇文章的原因。

那是一個單片機的C++程序,涉及到一個二重指針數組,類型是一個定義了虛函數的基類,通過指針調用虛函數。數據結構並不復雜,邏輯肯定不會出錯,但是程序跑飛了。

一開始覺得是初始化的問題,就把所有全局變量換成單例模式創建,無果。然后加了許多調試語句,把問題定位到了解引用上。想了想指針解引用肯定不會出問題,就覺得問題在虛函數調用過程中的函數指針解引用上。把指針調用(動態綁定)換成對象調用(靜態綁定),果然程序就正常了。但函數指針解引用本質上是修改PC(程序計數器)寄存器,這種編譯器搞定的事情我也插不了手。換了新版本的編譯器,也沒有解決。

后面的探索就奇怪了起來。我發現給PCB加一個100uF的電容可以讓程序在燒寫后正常運行,但在重新上電后,一旦程序去調用那虛函數,單片機就會復位;如果把業務邏輯改簡單一點,有助於重新上電后正常工作,但沒有本質上解決問題。用了一些猥瑣操作后,我發現不是單片機復位而是程序回到起始處。這可能是未注冊而觸發的中斷導致的,但就算給所有中斷都指定了空函數,也還是沒有解決。

百思不得其解,調試了一整天都沒有成功。

幾個月后再來看這個中斷的項目,重新讀了一遍代碼,發現了這個初始值的問題,終於解決了。后面就很順了。

現在看來這個debug的過程一開始方向挺對的,后面的探索就慢慢差到十萬八千里外去了。

燒寫正常運行、上電不正常的奇怪現象也可以解釋了。單片機內置復位電路會在上電時給寄存器賦初值,但內存中的數據還是隨機的。程序燒寫前后內存中的數據被保留,之前的程序不知怎么把那一塊內存初始化好了,燒寫后就可以正常工作;而上電后那一塊內存里都是隨機值,對隨機數進行4次解引用(二重指針2次,虛函數調用2次),程序早就不知道跑哪里去了。可能是尋到合法地址空間以外去了,由於某些保護機制的存在,程序就回到了起始處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM