使用直接初始化与 std::initializer_list 时的不同说明

Different instructions when I use direct initialization vs std::initializer_list

我正在研究各种初始化方法,并评估它们为各种用例提供​​的开发人员体验及其性能影响。在这个过程中,我写了两段代码,一段是直接初始化,一段是初始化列表。

直接:

class C {
public:
    char* x;

    C() : x(new char[10] {'0','1'}) {}
};

C c;

初始化器列表:

#include <utility>
#include <algorithm>

class C {
public:
    char* x;

    C(std::initializer_list<char> il) {
        x = new char[10];
        std::copy(il.begin(), il.end(), x);
    }
};

C c = {'0','1'};

我期待 std::initializer_list 生成相同的程序集,虽然我能理解为什么它可能更糟(看起来更复杂),但如果它实际上更糟,我会在这里问一个非常不同的问题。当我看到它用更少的指令生成 更好 代码时,想象一下我的惊讶吧!

Link 用上面的代码片断 - https://godbolt.org/z/i3XZ_K

直接:

_GLOBAL__sub_I_c:
        sub     rsp, 8
        mov     edi, 10
        call    operator new[](unsigned long)
        mov     edx, 12592
        mov     WORD PTR [rax], dx
        mov     QWORD PTR [rax+2], 0
        mov     QWORD PTR c[rip], rax
        add     rsp, 8
        ret
c:
        .zero   8

初始化器列表:

_GLOBAL__sub_I_c:
        sub     rsp, 8
        mov     edi, 10
        call    operator new[](unsigned long)
        mov     edx, 12592
        mov     QWORD PTR c[rip], rax
        mov     WORD PTR [rax], dx
        add     rsp, 8
        ret
c:
        .zero   8

除额外的 mov QWORD PTR [rax+2], 0 指令外,程序集几乎相同,乍一看,该指令看起来像是用空字符终止 char 数组。但是,IIRC 只有字符串文字(如 "01")会自动以空字符终止,而不是字符数组文字。

如果能深入了解为什么生成的代码不同,以及我能做些什么(如果可能)使直接案例更好,我将不胜感激。

另外,我是 x86 汇编的菜鸟,所以如果我遗漏了一些明显的东西,请告诉我。

编辑:如果我添加更多字符,情况只会变得更糟 - https://godbolt.org/z/e8Gys_

两个示例代码片段的效果不同。

new char[10] {'0','1'}

这个聚合初始化新的char数组,这意味着数组中所有在大括号括起来的初始化列表中没有给出初始化的元素都被初始化为零。

x = new char[10];

这不会将新数组的任何元素设置为任何值,并且

std::copy(il.begin(), il.end(), x);

只设置std::initializer_list.

中实际指定的元素

因此在第一个版本中,编译器必须保证所有没有指定初始值设定项的元素都设置为零,而在第二个版本中它可以保持这些值不变。

无法直接在 new 表达式中部分初始化数组。但是第二个例子的行为的明显再现会是这样的

C() : x(new char[10]) {
    constexpr char t[]{'0','1'};
    std::copy(std::begin(t), std::end(t), x);
}

虽然,真的,无论如何你都不应该直接使用 new。根据具体用例,改为使用 std::vector<char>std::array<char, 10>std::stringstd::unique_ptr<char[]>。所有这些都避免了 new 会导致的生命周期问题。