复制非POD类型的构造函数和普通构造函数

Copy constructor and normal constructor for non-POD type

本文关键字:构造函数 POD 类型 复制      更新时间:2023-10-16

有这样的代码:

#include <iostream>
class KlasaNiePOD{
public:
    int a;
    ~KlasaNiePOD(){}
};
int main() {
    KlasaNiePOD obiekt1; // first case
    std::cout << obiekt1.a << std::endl; // -1075234152
    KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case
    std::cout << obiekt2.a << std::endl; // 0
    return 0;
} 

为什么在第一种情况下"a"没有初始化,而在第二种情况下它初始化了?不应该总是在非POD类中调用构造函数吗?

编辑:

来自组件的片段:

.globl main
    .type   main, @function
main:
.LFB960:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    .cfi_lsda 0x0,.LLSDA960
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    pushl   %esi
    pushl   %ebx
    subl    $40, %esp
    movl    28(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $_ZSt4cout, (%esp) # std::cout << obiekt1.a << std::endl;
.LEHB0:
    .cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xf8,0x22
    .cfi_escape 0x10,0x6,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22
    call    _ZNSolsEi
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEPFRSoS_E
.LEHE0:
    movl    $0, 24(%esp) # Here obiekt2.a = 0
    movl    24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $_ZSt4cout, (%esp) # std::cout << obiekt2.a << std::endl;
.LEHB1:
    call    _ZNSolsEi
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEPFRSoS_E
.LEHE1:
    movl    $0, %ebx
    leal    24(%esp), %eax
    movl    %eax, (%esp)
    call    _ZN11KlasaNiePODD1Ev
    leal    28(%esp), %eax
    movl    %eax, (%esp)
    call    _ZN11KlasaNiePODD1Ev
    movl    %ebx, %eax
    addl    $40, %esp
    popl    %ebx
    popl    %esi
    movl    %ebp, %esp
    popl    %ebp
    ret
KlasaNiePOD obiekt1; // first case

这是默认初始化;由于它没有默认的构造函数,所以具有基本类型(包括数字类型)的成员是未初始化的。

KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case

临时KlasaNiePOD()是初始化的;由于它没有默认的构造函数,所以具有数字类型的成员被初始化为零。

该标准定义了几种不同类型的初始化,取决于上下文。零初始化将所有成员设置为0(转换为适当的类型,因此指针将设置为null指针值,即使空指针不全是零位);不构造函数被调用。默认初始化调用默认构造函数,默认情况下不会执行任何操作。值初始化如果存在用户定义的构造函数,则调用默认构造函数,但是如果没有用户定义的构造函数。初始值设定项为的对象简单地对CCD_ 2(空列表)进行值初始化。具有静态的对象生存期在程序启动前初始化为零(始终);如果它有非平凡构造函数,稍后将调用其构造函数(但在进入main之前)。未定义的所有其他对象初始化器默认初始化。

在您的代码中,obiekt1是默认初始化的;在这种情况下,无操作(使成员未初始化)。obiekt2通过复制初始化临时初始化的值;值初始化将CCD_ 6设置为0。(实际副本可能会进行优化,并进行值初始化直接发生在物体上。)

ISO 14882:2011(e)8.5.1:

聚合是一个没有用户提供的数组或类(第9条)构造函数(12.1),非静态数据没有大括号或等号成员(9.2),没有私有或受保护的非静态数据成员(第条11) ,没有基类(第10条),也没有虚拟函数(10.3)。

因此,您的类是一个集合。

KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case

将调用聚合,最后调用值初始化,导致int初始化为零。

添加

KlasaNiePOD(){}

到您的类定义,您将看到0的设置将消失(因为这将使它不再是聚合)。