可能放置"新"依赖于底层存储价值?

Mat*_* M. 8 c++ optimization language-lawyer

让我们从一些背景开始.

自定义内存池使用类似于以下内容的代码:

struct FastInitialization {};

template <typename T>
T* create() {
    static FastInitialization const F = {};

    void* ptr = malloc(sizeof(T));
    memset(ptr, 0, sizeof(T));
    new (ptr) T(F);
    return reinterpret_cast<T*>(ptr);
}
Run Code Online (Sandbox Code Playgroud)

这个想法是,当调用时FastInitialization,构造函数可以假设存储已经零初始化,因此只初始化那些需要不同值的成员.

然而,GCC(至少6.2和6.3)有一个"有趣"的优化.

struct Memset {
    Memset(FastInitialization) { memset(this, 0, sizeof(Memset)); }

    double mDouble;
    unsigned mUnsigned;
};

Memset* make_memset() {
    return create<Memset>();
}
Run Code Online (Sandbox Code Playgroud)

编译为:

make_memset():
        sub     rsp, 8
        mov     edi, 16
        call    malloc
        mov     QWORD PTR [rax], 0
        mov     QWORD PTR [rax+8], 0
        add     rsp, 8
        ret
Run Code Online (Sandbox Code Playgroud)

但:

struct DerivedMemset: Memset {
    DerivedMemset(FastInitialization f): Memset(f) {}

    double mOther;
    double mYam;
};

DerivedMemset* make_derived_memset() {
    return create<DerivedMemset>();
}
Run Code Online (Sandbox Code Playgroud)

编译为:

make_derived_memset():
        sub     rsp, 8
        mov     edi, 32
        call    malloc
        mov     QWORD PTR [rax], 0
        mov     QWORD PTR [rax+8], 0
        add     rsp, 8
        ret
Run Code Online (Sandbox Code Playgroud)

也就是说,只有struct与其基数对应的部分的前16个字节已被初始化.调试信息确认调用memset(ptr, 0, sizeof(T));已完全省略.

另一方面,ICC和Clang都调用memset全尺寸,这是Clang的结果:

make_derived_memset():               # @make_derived_memset()
        push    rax
        mov     edi, 32
        call    malloc
        xorps   xmm0, xmm0
        movups  xmmword ptr [rax + 16], xmm0
        movups  xmmword ptr [rax], xmm0
        pop     rcx
        ret
Run Code Online (Sandbox Code Playgroud)

所以GCC和Clang的行为有所不同,问题就变成了:GCC是否正确并且产生了更好的装配,或者是Clang是否正确和GCC车?


或者,就语言律师而言:

在哪种情况下,构造函数可以依赖存储在其分配的存储中的先前值?

注意:我认为这仅适用于展示位置new,但我很高兴以其他方式展示.

Bar*_*rry 11

可能放置new依赖于底层存储价值?

不,它可能不会.来自[dcl.init]:

如果没有为对象指定初始化程序,则默认初始化该对象.当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,并且如果没有对该对象执行初始化,则该对象保留不确定的值,直到该值被替换(5.18).

不确定的价值就是那个,不确定的.这并不意味着,在放置新表达式的情况下,必须保持先前的存储器.允许编译器对内存执行任何操作 - 包括但不限于任何内容.

在哪种情况下,构造函数可以依赖存储在其分配的存储中的先前值?

在[dcl.init]列表案件的后续款,其中的行为是产生不确定的值时,但他们只有无符号窄字符类型做不确定的.

所以,在任何情况下.