嵌套聚合中的成员错误初始化? (MSVC)

问题描述 投票:0回答:1

以下代码的输出让我感到惊讶。我的期望是

Inner
会将
num1
初始化为 10(事实上),然后
num2
将被初始化,复制
num1
的值 10。因此输出将是
10 10
。相反,我得到
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
似乎复制了未初始化的内存(或者来自错误的地址?)。它接收
Outer
的成员
a
的值,无论该值是 4 还是 0xFFFFFFFFFFFFFFFF。

编译器是MSVC 19.37.32825.0。例如通过运行

cl main.cpp /std:c++latest /EHsc /O2 /link /out:program.exe
进行编译。

使用 clang++ 或 g++,我得到了预期的结果,

10 10
。编译器错误还是我的误解?

其他一些变化的影响:

  • Inner() {}
    添加构造函数
    Inner
    -> 输出变为
    10 10
  • Inner inner{}
    更改为
    Inner inner{11, 12}
    -> 输出变为
    11 12
    (预期)
  • Inner inner{}
    更改为
    Inner inner{11}
    -> 输出变为
    11 4
  • 返回
    {}
    而不是
    {.a = 4}
    -> 输出变为
    10 10
  • 直接在
    Inner inner{}
    中创建
    main
    并打印其成员 -> 输出变为
    10 10
c++ visual-c++ c++20 undefined-behavior
1个回答
0
投票

这是一个编译器错误。

makeOuter()
翻译为

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

如果改变了

Outer makeOuter() {
    return {.a = 4, .inner = {}};
}

然后翻译成

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

https://godbolt.org/z/vdb4Yv6n8

© www.soinside.com 2019 - 2024. All rights reserved.