Update: Since this appears to be a compiler bug, I've submitted a report to Microsoft.
The output of the following code surprises me. My expectation is that Inner
would have num1
initialized to 10 (as it is) and then num2
would be initialized, copying num1
's value of 10. So the output would be 10 10
. Instead, I get 10 4
.
#include <iostream>
struct Inner {
uint64_t num1{10};
uint64_t num2{num1};
};
struct Outer {
uint64_t a{};
Inner inner{};
};
Outer makeOuter() {
return {.a = 4};
}
int main(int argc, char* argv[]) {
auto outer = makeOuter();
std::cout << outer.inner.num1 << " " << outer.inner.num2 << std::endl;
return 0;
}
num2
appears to copy uninitialized memory (or from the wrong address?). It receives the value of Outer
's member a
, whether that is made to be 4 or 0xFFFFFFFFFFFFFFFF.
The compiler is MSVC 19.37.32825.0. Compile for example by running cl main.cpp /std:c++latest /EHsc /O2 /link /out:program.exe
.
With clang++ or g++, I get the expected result, 10 10
. Compiler bug or my misunderstanding?
The effects of some other changes:
Inner() {}
to Inner
-> output becomes 10 10
Inner inner{}
to Inner inner{11, 12}
-> output becomes 11 12
(expected)Inner inner{}
to Inner inner{11}
-> output becomes 11 4
{}
instead of {.a = 4}
-> output becomes 10 10
Inner inner{}
directly in main
and printing its members -> output becomes 10 10
It's a compiler bug.
makeOuter()
is translated into
Outer makeOuter(void) PROC ; makeOuter, COMDAT
mov eax, DWORD PTR __$ReturnAddress$[esp-4]
mov DWORD PTR [eax], 4
mov DWORD PTR [eax+4], 0
mov DWORD PTR [eax+8], 10 ; 0000000aH
mov DWORD PTR [eax+12], 0
mov DWORD PTR [eax+16], 4 ; <-- HERE
mov DWORD PTR [eax+20], 0
ret 0
Outer makeOuter(void) ENDP ; makeOuter
If it's changed like
Outer makeOuter() {
return {.a = 4, .inner = {}};
}
then it's translated into
Outer makeOuter(void) PROC ; makeOuter, COMDAT
mov eax, DWORD PTR __$ReturnAddress$[esp-4]
mov DWORD PTR [eax], 4
mov DWORD PTR [eax+4], 0
mov DWORD PTR [eax+8], 10 ; 0000000aH
mov DWORD PTR [eax+12], 0
mov DWORD PTR [eax+16], 10 ; 0000000aH
mov DWORD PTR [eax+20], 0
ret 0
Outer makeOuter(void) ENDP ; makeOuter