按需合成构造函数

复制、默认构造都是按需生成的。对于平凡的情况不需要生成,只是在语意上满足“拥有构造函数”的含义。

x86-64 gcc 13.1 -std=c++20

struct Point {
    int x;
    int y;
    Point() = default; // 即便显式声明了默认构造函数,也不会合成
};

int main() {
    auto some_point = Point{}; // {}初始化对聚合类有清零的效果
}
main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-8], 0
        mov     DWORD PTR [rbp-4], 0
        mov     eax, 0
        pop     rbp
        ret

修改 Point 的定义:

struct Point {
    int x{}; // 只修改了这里,结果合成了默认构造函数
    int y;
    Point() = default;
};

int main() {
    auto some_point = Point{};
}
Point::Point() [base object constructor]:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], 0
        nop
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-8], 0
        mov     DWORD PTR [rbp-4], 0
        lea     rax, [rbp-8]
        mov     rdi, rax
        call    Point::Point() [complete object constructor]
        mov     eax, 0
        leave
        ret

接下来删掉默认构造函数的声明:

struct Point {
    int x{};
    int y;
        // 删掉了默认构造函数声明,结果不再合成默认构造函数
};

int main() {
    auto some_point = Point{};
}
main:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], 0
        mov     eax, 0
        pop     rbp
        ret

构造函数和成员默认值同时出现时,就会合成默认构造函数。这个和书中的描述是相符的,因为有成员默认值时,默认构造函数需要特别处理一些内容。

接下来:

struct Point {
    int x{};
    int y;
};

int main() {
    auto some_point = Point(); // 注意花括号变成了圆括号
}
Point::Point() [base object constructor]:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], 0
        nop
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-8], 0
        mov     DWORD PTR [rbp-4], 0
        lea     rax, [rbp-8]
        mov     rdi, rax
        call    Point::Point() [complete object constructor]
        mov     eax, 0
        leave
        ret

显式使用构造函数相当于声明了构造函数。

不过但凡用上 -O1 级别的优化,空的默认构造函数就可以被内联。