7

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

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 中查看生成的汇编代码。不过,在发布版本中可能很难遵循。

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

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

4

5 回答 5

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 有一个很好的细分。

于 2011-02-23T21:50:40.077 回答
10

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

于 2011-02-23T21:49:29.007 回答
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。所以你必须自己检查拆卸。但结果应该是相似的。

祝你好运!

于 2011-02-23T21:58:36.260 回答
1

某些类或结构类型在 C++ 中称为 POD“Plain Old Data”。这些类型不会调用构造函数。

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

于 2011-02-23T21:50:50.647 回答
0

您的示例不是很好,您错过了public示例类中的关键字,而且在您的示例中,通过编写CLASS * class = new CLASS();而不是CLASS * class = new CLASS;.

在您所说的代码中 - 将始终按照标准要求执行零初始化。你可以随意调用它——但是会有代码来保证标准的规则。

如果您在没有显示这个有争议的示例代码的情况下提问 - 那么唯一正确的答案将是 - compiler specific

于 2011-02-23T22:10:33.510 回答