[心得] Class 非靜態成員初始化順序

看板C_and_CPP (C/C++)作者 (mike)時間3年前 (2021/09/06 06:32), 編輯推噓7(706)
留言13則, 9人參與, 3年前最新討論串1/1
論壇版: https://forum.community.tw/t/topic/158 新設立的論壇,也可當作部落格的留言系統 歡迎大家來試試看 另外想問大家對於問答區有興趣嗎? 以下正文 這一篇是把之前自己遇到的問題記錄下來,雖然現在看來有點蠢,但當時還是花了一 些時間才找出來 經歷 在檢測單元測試時,發現有一項測試,在 CI/CD 中會隨機出錯,一開始想說這種隨機錯 誤通常是沒有初始化,或者一些陣列操作超出範圍,導致記憶體被意外修改了。在 linux 又很難重現,只有在 github action MSVC 中出錯,又當時沒有手邊沒有 MSVC 能 夠直接使用,導致一開始方向並沒有很明確,檢查了初始化跟陣列操作都也正確,最後才 發現某一項初始化在第一項測試不一定能夠歸零,但第二項之後都可以正確歸零,所以才 開始懷疑初始化的順序,然後在查了一些資料後確認 class non-static data (非靜態成 員) 初始化順序是根據宣告順序,而非直接使用 constructor 的順序 參考資料 https://en.cppreference.com/w/cpp/language/constructor 中的 Initialization order 的第三項 Then, non-static data member are initialized in order of declaration in the class definition. 例子(論壇版有自動上色的範例) ``` #include <iostream> class test { public: test(int val) : b(val), a(b) {} // many codes int a; int b; }; int main() { test k(3); std::cout << k.a << " " << k.b << std::endl; return 0; } ``` 以上是一個簡單的例子,在 constructor 後面 member initializers 是使用 b(val), a(b),當 class 中間又有更多函式時,在看 constructor 時,是會看不到宣告順序的, 所以我當時就直覺認為會是 b 先被給定 val 然後 a 再被給定 b 也就是 val,然而這是 錯的。 想像輸出會是 3 3 實際情形 在前面有提過他是根據宣告順序,而非 member initializers 怎麼寫 (constructor 後 面 {} 之前),所以這邊實際的運作會是,a 被給定 b (未定) , b 再被給定 val,因 此 a 的值會根據 b 一開始為初始化的值而決定。 因此實際輸出會是 * 3 而在這邊 * 在 linux 為初始化地很常會是零 (個人經驗),又剛好我的初始化是要歸零 ,導致在 linux 的部分很難遇到這樣的問題,幸好在 MSVC 有指出這樣的問題。 檢查 後來有分享這件事給同實驗室的,他們也給出了一項編譯器選項,可以指出這項問題 -Wreorder,就會指出例子中的 test::b 會在 test::a 之後初始化 https://imgur.com/pj3sOQR.png
可以很迅速地發現這項問題,也可以透過 https://godbolt.org/z/Edjc161sK 來看 結語 class non-static data member 在 member initializers 中初始化順序是根據宣告順序 來定,可以用 -Wreorder 來檢查,以上是之前遇到的問題分享。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 46.223.163.145 (德國) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1630881157.A.38C.html

09/06 07:08, 3年前 , 1F

09/06 07:10, 3年前 , 2F
雖然是簡體字,但是講得很詳細
09/06 07:10, 2F

09/06 07:16, 3年前 , 3F
這故事告訴我們,平常 warning 要開好開滿XD
09/06 07:16, 3F

09/06 10:30, 3年前 , 4F
推長知識
09/06 10:30, 4F

09/06 16:56, 3年前 , 5F
如果用CI/CD的話 gcc, msvc, clang workflow 都用
09/06 16:56, 5F

09/06 16:57, 3年前 , 6F
總有一個compiler會抓到
09/06 16:57, 6F

09/06 19:49, 3年前 , 7F
我記得蠻多書都講過這吧?c++兩本經典教學都講過
09/06 19:49, 7F

09/06 20:16, 3年前 , 8F
這次就是msvc有抓到XD (幸好
09/06 20:16, 8F

09/07 16:29, 3年前 , 9F
Effective C++ 2nd Ed. 條款 13: Initialization list中
09/07 16:29, 9F

09/07 16:30, 3年前 , 10F
的members初始化次序應該和其在class內的宣告次序相同。
09/07 16:30, 10F

09/07 16:31, 3年前 , 11F
第三版把這件事合併進條款 4 當中了。
09/07 16:31, 11F

09/08 19:15, 3年前 , 12F
推推
09/08 19:15, 12F

09/10 02:48, 3年前 , 13F
用vscode 搭配clangd 的話是會直接提出警告的
09/10 02:48, 13F
文章代碼(AID): #1XDKM5EC (C_and_CPP)
文章代碼(AID): #1XDKM5EC (C_and_CPP)