2014-02-20 40 views
2

最近我想到,我經常想承認的一個「偶爾出現的奇怪的bug」的修正是簡單地初始化一個成員變量我忘了添加到初始化列表中。包裝內置的C++類型以保證初始化

爲了避免將來在這類錯誤上浪費時間,我一直在嘗試着完全拋棄內置的原始類型,並用包裝類代替它們,它們的行爲與原始類型完全相同,只是它們會總是被初始化。

我在C++中足夠精通,知道我可以編寫非常接近該目標的類。即我相信我可以寫一個MyInt類,它的行爲非常像一個真正的int。但是我也知道C++已經足夠了,知道可能有一兩件事情會遺漏;)

有沒有人做過類似這樣的事情?任何指向相關文檔的指針,或要注意的陷阱列表?這是一個好主意,還是我沒有看到任何缺點?

謝謝!

編輯:謝謝大家對您的意見,這裏是一個更新。我開始玩Jarod42的包裝片段,看看我是否可以轉換一個小型的業餘愛好項目代碼庫。不是完全意外的,這是一個PITA,但可能是可行的。儘管如此,它開始感覺像是一個非常大的錘子。

編譯器警告不是一個真正的選擇,因爲只有一個(-WeffC++)似乎發現問題,它只存在於gcc中,即這不是一個安全的便攜式解決方案。

到目前爲止,我的結論是開始使用C++ 11的所有原始成員的類初始化,如下面的Praetorian所建議的。即像

struct C { 
    int x = 0; // yay C++11! 
}; 

..並希望經過一段時間後,ommitting例如初始化的感覺那麼「裸」作爲一個函數內聲明的代碼unititialized變量(我已經不再做以前很長一段時間)。這似乎比嘗試將初始化程序列表更新爲最新更容易出錯,因爲它正好與聲明一起。

+0

這聽起來像你不想使用C++ ... – BoBTFish

+1

爲什麼不使用像cppcheck這樣的靜態代碼檢查器,它會發現這個問題和其他許多問題? –

+0

主要的缺點是性能。大多數編譯器都會在寄存器中返回一個「int」,但不會返回寄存器中的類類型,不管它有多簡單。但是,如果你限制你的包裝類型類成員... –

回答

2

C++ 11使它很容易通過允許類的非靜態數據成員的初始化避免這一缺陷。例如:

struct foo 
{ 
    foo(int i) : i(i) {} // here i will be set to argument value 
    foo() {}    // here i will be zero 

    int i = {};    // value (zero) initialize i 
}; 

此功能也不限於微不足道的類型。所以,只要你在類定義中聲明它們,就開始初始化數據成員。

如果您的編譯器不支持此功能,請嘗試啓動警告級別以查看它是否會告訴您有關未初始化的數據成員。例如,g ++有-Weffc++標誌,它會警告你未初始化的數據成員(等等)。

嘗試接下來的事情將是一個靜態分析工具來捕獲這些錯誤。

總而言之,在進行每一個微不足道的數據類型裝箱之前,我會嘗試幾件事情。

+0

有趣的是,不知道在課堂上的初始化。需要一段時間才能習慣它,你總是會自動地「做」而不去思考,但是我也會拋棄內置類型...... – lespalt

+0

-WeffC++很有趣,但它似乎並不工作蘋果公司的llvm-g ++ ..我也不知道VC等價物。 – lespalt

+0

@ user3333631這不就是一個別名嗎?你是對的,鏗鏘聲對未初始化的成員沒有發出警告,但說實話,這個標誌太嘈雜,無法打開任何體面大小的代碼庫。 – Praetorian

1

這是一個更容易只要打開編譯器警告。大多數體面的編譯器會警告您使用未初始化的變量 - 授予編譯器可能會錯過的幾個邊緣情況。

+0

VC++和g ++都沒有提到他提到的情況(在構造函數中忘記了一個成員變量)。這是'/ W3'或'/ Wall'。 –

1

嘗試更好的調試。

您可以打開未初始化變量的編譯器警告(請參閱this SO question)。

您還可以使用執行此操作的程序和其他代碼檢查(靜態分析),如cppcheck,其中列出了未初始化的變量。

也嘗試改變你的代碼。在C++中,您可以控制何時分配內存,使用哪些構造函數等等。如果你編寫的風格是用部分數據構造對象,然後再填充其他部分,那麼你很可能會遇到未初始化的變量。但是,如果你確保所有的構造函數都構造了一個有效的對象,並且避免了多個事實點(參見Single Point Of Truth原理),那麼你的錯誤更有可能被編譯器捕獲 - 你會有將一個未初始化的變量作爲一個值傳遞(VC++會警告你),或者在你的構造函數調用中有錯誤的數字或類型的東西(編譯錯誤)等。

可能我建議你挑選最近的這類事情的來源,是否有連接你的結構鏈,並問你如何更好地重構它?在C++中有一種特別嚴格的編碼風格,它最大限度地利用了編譯器,因此儘可能早地提示您。真的,使用該風格時創建的錯誤不應少於多線程問題,資源問題等。

我擔心如果初始化所有內容只是爲了防止出現此類錯誤,您將錯過了解遵守規範的風格比未初始化的變量延伸得更遠。

1

以下可能會有所幫助:

template <typename T> 
class My 
{ 
public: 
    constexpr My() : t() {} 
    constexpr My(const T&t) : t(t) {} 
    operator T&() { return t; } 
    constexpr operator const T&() const { return t; } 

    const T* operator&() const { return &t; } 
    T* operator&() { return &t; } 
private: 
    T t; 
}; 

注知道這是更好地檢查My<int>代替每個可能未初始化int的使用...

但是請注意,你必須做特殊工作反正union

+0

謝謝,這看起來很酷。幾乎我所想的,但更優雅(與constexpr)。這是經過戰鬥測試的代碼還是你剛剛編譯好的代碼?你能想到任何情況下,我的不會像一個整數? – lespalt

+0

即時完成(有一些測試)。他們不會與模板專業化行爲相同:'std :: is_integral > :: value!= std :: is_integral :: value' ... – Jarod42