class 非靜態成員初始化順序
the initialization order of class non-static data member is the order of declaration in the class.
這一篇其實是把自己之前遇到的問題記錄下來,雖然現在看來有點蠢,但當時還是花了一些時間才找出來
經歷
在檢測單元測試時,發現有一項測試,在 CI/CD 中會隨機出錯,一開始想說這種隨機錯誤通常是沒有初始化,或者一些陣列操作超出範圍,導致記憶體被意外修改了。在 linux 又很難重現,只有在 github action MSVC 中出錯,又當時沒有手邊沒有 MSVC 能夠直接使用,導致一開始方向並沒有很明確,檢查了初始化跟陣列操作都也正確,最後才發現某一項初始化在第一項測試不一定能夠歸零,但第二項之後都可以正確歸零,所以才開始懷疑初始化的順序,然後在查了一些資料後確認 class non-static data (非靜態成員) 初始化順序是根據宣告順序,而非直接使用 constructor 的順序
參考資料 cppreference 中的 Initialization order 的第三項 Then, non-static data member are initialized in order of declaration in the class definition.
完整的也貼在這邊方便參考
The order of member initializers in the list is irrelevant: the actual order of initialization is as follows:
- If the constructor is for the most-derived class, virtual bases are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)
- Then, direct bases are initialized in left-to-right order as they appear in this class's base-specifier list
- Then, non-static data member are initialized in order of declaration in the class definition.
- Finally, the body of the constructor is executed
例子
#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
之後初始化

可以很迅速地發現這項問題,也可以透過此連結來看這個例子
結語
class non-static data member 在 member initializers 中初始化順序是根據宣告順序來定,可以用 -Wreorder
來檢查,以上是之前遇到的問題分享。