msvc 的动态数组初始化行为不同于 gcc 和 clang

Tim*_*imo 5 c++ gcc clang visual-c++ c++17

鉴于类型

struct S
{
    int x;
};
Run Code Online (Sandbox Code Playgroud)

和两个函数

S* f()
{
    const auto x = new S[1] { { 42 } };
    return x;
}

S* g() 
{
    const auto x = new S[1];
    x[0] = {42};
    return x;
}
Run Code Online (Sandbox Code Playgroud)

人们会认为fg行为相同。根据这个答案 f应该执行聚合初始化,x这将导致相同的行为。纵观组装铛的和gcc这似乎是真实的,并都fg产生完全相同的组件。

但是,我猜 msvc 不想这样做。msvc for 的汇编g类似于 clang 和 gcc,但f它似乎完全忽略了初始化程序:

S * f(void) PROC                                    ; f, COMDAT
        mov     ecx, 4
        jmp     void * operator new[](unsigned __int64)                     ; operator new[]
S * f(void) ENDP                                    ; f

S * g(void) PROC                                    ; g, COMDAT
$LN4:
        sub     rsp, 40                             ; 00000028H
        mov     ecx, 4
        call    void * operator new[](unsigned __int64)               ; operator new[]
        mov     DWORD PTR [rax], 42                 ; 0000002aH
        add     rsp, 40                             ; 00000028H
        ret     0
S * g(void) ENDP                                    ; g
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我们Sintmsvc替换执行初始化,但还添加了一些额外的指令(我不明白,也许有人可以对此有所了解)。

int * f(void) PROC                                 ; f, COMDAT
$LN6:
        sub     rsp, 40                             ; 00000028H
        mov     ecx, 4
        call    void * operator new[](unsigned __int64)               ; operator new[]
        test    rax, rax
        je      SHORT $LN3@f
        mov     DWORD PTR [rax], 42                 ; 0000002aH
        add     rsp, 40                             ; 00000028H
        ret     0
$LN3@f:
        add     rsp, 40                             ; 00000028H
        ret     0
int * f(void) ENDP                                 ; f
Run Code Online (Sandbox Code Playgroud)

是一个完整的例子。

在这种情况下,标准的符合行为是什么?那些额外的汇编指令在f做什么(如果我们替换Sint)?

编辑

错误已报告并可在此处跟踪。