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

作者: mikemike1021 (mike)   2021-09-06 06:32:33
論壇版: 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 來檢查,以上是之前遇到的問題分享。
作者: zebracoco (公子吃丙)   2021-09-06 07:08:00
https://i.imgur.com/3D0JLFq.jpg雖然是簡體字,但是講得很詳細
作者: Lipraxde (Lipraxde)   2021-09-06 07:16:00
這故事告訴我們,平常 warning 要開好開滿XD
作者: mmmmei (mmm煤)   2021-09-06 10:30:00
推長知識
作者: pponywong (pony)   2021-09-06 16:56:00
如果用CI/CD的話 gcc, msvc, clang workflow 都用總有一個compiler會抓到
作者: final01 (牛頓運動定律)   2021-09-06 19:49:00
我記得蠻多書都講過這吧?c++兩本經典教學都講過
作者: mikemike1021 (mike)   2021-09-06 20:16:00
這次就是msvc有抓到XD (幸好
作者: closer76 (克樓瑟)   2021-09-07 16:29:00
Effective C++ 2nd Ed. 條款 13: Initialization list中的members初始化次序應該和其在class內的宣告次序相同。第三版把這件事合併進條款 4 當中了。
作者: howareuuu   2021-09-08 19:15:00
推推
作者: youchenliu (柚子味的豆花)   2021-09-10 02:48:00
用vscode 搭配clangd 的話是會直接提出警告的

Links booklink

Contact Us: admin [ a t ] ucptt.com