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.debug

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

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

To default-initialize an object of type T means:code

  • 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);orm

  • 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次),程序早就不知道跑哪裏去了。多是尋到合法地址空間之外去了,因爲某些保護機制的存在,程序就回到了起始處。

相關文章
相關標籤/搜索