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

发布于 2024-10-18 14:40:58 字数 905 浏览 5 评论 0原文

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

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

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

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

I have a general question, that may be a little compiler-specific.
I'm interested in the conditions under which a constructor will be called. Specifically, in release mode/builds optimised for speed, will a compiler-generated or empty constructor always be called when you instantiate an object?

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?
}

I've done a lot of searching, and spent some time looking through the generated assembly code in Visual Studio. It can be difficult to follow in release builds though.

In summary:
Is the constructor always called? If so, why?

I understand this will very much depend on the compiler, but surely there's a common stance. Any examples/sources you can cite would be really appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

眼角的笑意。 2024-10-25 14:40:58

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

不会。如果您的类是所谓的“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++ 常见问题解答有很好的细分

will a compiler generated constructor/empty constructor always be called when you instantiate an object?

No. If your class is a so-called “POD” (plain old data) then the compiler-generated constructor won’t always be called.

Specifically, it won’t be called in the two following cases:

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.
}

The conditions for when exactly a type is a POD are a bit tricky. The C++ FAQ has a nice breakdown.

暗地喜欢 2024-10-25 14:40:58

从逻辑上讲,构造函数被调用。在生成的代码中,如果构造函数不执行任何操作,则不会有可以追溯到构造函数的指令,除非您的编译器非常不擅长优化并插入对仅返回的内容的调用。

Logically, the constructor is called. In generated code, if the constructor does nothing, there will be no instructions that can be traced back to the constructor, unless your compiler is very very bad at optimizing and inserts a call to something that just returns.

甜心小果奶 2024-10-25 14:40:58

在优化模式下,如果您的类或结构是 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。所以你必须自己拆机检查。但结果应该是相似的。

祝你好运!

When in optimizing mode, if your class or structure is POD (has only POD types) and constructor is not specified, any production quality C++ compiler will not only skip the call to a constructor but not even generate it.

If your class has non-POD members who's constructor(s) have to be called, compiler will generate default constructor that calls member's constructors. But even then - it will not initialize POD types. I.e. if you don't initialize member explicitly, you may end up with garbage there.

The whole thing can get even fancies if your compiler/linker has LTO.

Hope it helps! And make your program work first, then use a profiler to detect slow places, then optimize it. Premature optimization may not only make your code unreadable and waste tons of your time, but could also not help at all. You have to know what to optimize first.

Here is a disassembly for code in your example (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

As you can see, there are no constructors called at all. There are no classes at all, every object is just a 4 bytes integer.

With MS compiler, YMMV. So you have to check disassembly yourself. But result should be similar.

Good luck!

枯叶蝶 2024-10-25 14:40:58

某些类或结构类型在 C++ 中称为 POD“普通旧数据”。这些类型不会调用构造函数。

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

Certain class or struct types are called POD "Plain Old Data" in C++. These types will not have constructors called.

The rules for being a POD are important enough that you should look them up, but in summary: only contains primitive data types and has no defined constructors.

水水月牙 2024-10-25 14:40:58

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

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

如果您在没有显示此有争议的示例代码的情况下提出问题 - 那么唯一正确的答案将是 - 特定于编译器

Your sample isn't very good, you've missed the public keyword in sample classes and moreover in your examples force zero-initialization by writing CLASS * class = new CLASS(); instead of CLASS * class = new CLASS;.

In the code as you put it - zero-initialization will always be performed as it is required by the standard. You can call it as you want - but there WILL be code to guarantee the rules of the standard.

If you had asked without showing this controversial sample code - then the only correct answer would be - compiler specific.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文