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

时间:2012-01-06 13:22:44

标签: c++

有这段代码:

#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

3 个答案:

答案 0 :(得分:5)

KlasaNiePOD obiekt1; // first case

这是默认初始化;因为它没有默认构造函数,所以具有基本类型(包括数字类型)的成员将保持未初始化状态。

KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case

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

答案 1 :(得分:3)

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

在您的代码中,obiekt1是默认初始化的;在这种情况下,一个无操作 (让成员未初始化)。 obiekt2由副本初始化 价值初始化临时;值初始化将a设置为 0.(可以使用值初始化优化实际副本 直接发生在物体上。)

答案 2 :(得分:1)

ISO 14882:2011(e)8.5.1:

  

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

因此,您的班级是聚合。

KlasaNiePOD obiekt2 = KlasaNiePOD(); // second case

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

添加

KlasaNiePOD(){}

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