是否总是在C ++中调用空构造函数?

时间:2011-02-23 21:43:01

标签: c++ constructor compiler-optimization default-constructor

我有一个普遍的问题,可能是一个特定的编译器。 我对调用构造函数的条件感兴趣。具体来说,在发布模式/为速度优化的版本中,在实例化对象时是否总是会调用编译器生成的或空的构造函数?

class NoConstructor  
{  
    int member;  
};  

class EmptyConstructor  
{  
    int member;  
};

class InitConstructor  
{  
    InitConstructor()  
        : member(3)   
    {}  
    int member;  
};

int main(int argc, _TCHAR* argv[])  
{  
    NoConstructor* nc = new NoConstructor(); //will this call the generated constructor?  
    EmptyConstructor* ec = new EmptyConstructor(); //will this call the empty constructor?  
    InitConstructor* ic = new InitConstructor(); //this will call the defined constructor  

    EmptyConstructor* ecArray = new EmptyConstructor[100]; //is this any different?
}

我已经做了很多搜索,并花了一些时间查看Visual Studio中生成的汇编代码。但是在发布版本中可能很难遵循。

总结: 构造函数总是被调用吗?如果是这样,为什么?

我知道这很大程度上取决于编译器,但肯定有一个共同的立场。您可以引用的任何示例/来源都将非常感激。

5 个答案:

答案 0 :(得分:15)

  

在实例化对象时,是否会始终调用编译器生成的构造函数/空构造函数?

没有。如果您的类是所谓的“POD”(普通旧数据),则编译器生成的构造函数将不会始终被调用。

具体而言,在以下两种情况下不会调用它:

struct Pod {
    int x;
};

int main() {
    Pod pod;
    std::cout << pos.x << std::endl; // Value undefined.

    Pod pod2 = Pod(); // Explicit value initialization.


    Pod* pods = new Pod[10];
    // Values of `pods` undefined.

    Pod* pods2 = new Pod[10](); // Explicit value initialization.
}

何时类型是POD的条件有点棘手。 C++ FAQ has a nice breakdown

答案 1 :(得分:10)

逻辑上,调用构造函数。在生成的代码中,如果构造函数什么都不做,那么就没有可以追溯到构造函数的指令,除非你的编译器非常非常糟糕地优化并插入一个只返回的东西。

答案 2 :(得分:5)

当处于优化模式时,如果您的类或结构是POD(仅具有POD类型)并且未指定构造函数,则任何生产质量C ++编译器不仅会跳过对构造函数的调用,而且甚至不会生成它。

如果你的类有非POD成员,必须调用构造函数,编译器将生成调用成员构造函数的默认构造函数。但即便如此 - 它也不会初始化POD类型。即如果你没有明确地初始化member,那么你最终可能会有垃圾。

如果你的编译器/链接器有LTO,那么整个事情就会变得很奇怪。

希望它有所帮助!并使您的程序首先运行,然后使用分析器检测缓慢的位置,然后优化它。过早优化可能不仅会使您的代码难以理解并浪费大量时间,而且根本无法提供帮助。你必须先知道要优化什么。

以下是示例中代码的反汇编(x86_64,gcc 4.4.5):

main:
    subq    $8, %rsp
    movl    $4, %edi
    call    _Znwm
    movl    $4, %edi
    movl    $0, (%rax)
    call    _Znwm
    movl    $4, %edi
    movl    $0, (%rax)
    call    _Znwm
    movl    $400, %edi
    movl    $3, (%rax)
    call    _Znam
    xorl    %eax, %eax
    addq    $8, %rsp
    ret

如您所见,根本没有调用构造函数。根本没有类,每个对象只是一个4字节的整数。

使用MS编译器,YMMV。所以你必须自己检查一下拆卸。但结果应该是相似的。

祝你好运!

答案 3 :(得分:1)

某些类或结构类型在C ++中称为POD“Plain Old Data”。这些类型不会具有名为。

的构造函数

作为POD的规则非常重要,您应该查找它们,但总结一下:只包含原始数据类型,并且没有已定义的构造函数。

答案 4 :(得分:0)

您的示例不是很好,您错过了示例类中的public关键字,而且在您的示例中,通过编写CLASS * class = new CLASS();而不是CLASS * class = new CLASS;强制进行零初始化。

在您提供的代码中 - 始终按照标准的要求执行零初始化。您可以根据需要调用它 - 但是会有代码来保证标准的规则。

如果您在没有展示这个有争议的示例代码的情况下提出要求 - 那么唯一正确的答案就是 - compiler specific