什么时候调用构造函数?

Posted

技术标签:

【中文标题】什么时候调用构造函数?【英文标题】:When are constructors called? 【发布时间】:2009-01-17 00:04:59 【问题描述】:

如果我在函数的中途定义一个类的局部变量实例而不使用指针和 new,构造函数是在进入函数时调用还是在定义的位置调用?

如果我在文件中全局定义一个类的另一个实例,在第一次加载可执行文件时会调用该构造函数吗?如果多个线程正在访问 .dll 怎么办?

最后,你的答案在 .dll、.so、.exe 和 linux 可执行文件中是否相同?

【问题讨论】:

这是学习使用调试器的完美方式,在你的构造函数中放置一个断点(定义一些),看看它们何时被命中。 【参考方案1】:

如果我在函数的中途定义了一个类的局部变量实例,而不使用指针和 new,构造函数是在进入函数还是在哪里定义的时候被调用?

什么时候定义的。

如果我在文件中全局定义一个类的另一个实例,是否会在首次加载可执行文件时调用该构造函数?

是的。

如果多个线程正在访问 .dll 怎么办?

DLL 通常只为整个应用程序加载一次——事实上,DLL 也有一个入口点,由应用程序的线程调用,但全局变量初始化在此之前只发生一次。

【讨论】:

实际上,在 Windows 上,每个创建的线程都会调用 DLL 入口点(以允许创建线程本地存储)。不确定其他操作系统的 但是,DLL 中的全局变量只被构造一次:当第一次加载 DLL 时,以及在第一次加载 DLL 的线程的上下文中。 @zdan:对,对不起。让我纠正一下。实际上,我之前在 SO 上写过一次这个错误,并且也得到了纠正。【参考方案2】:

如果我在函数的中途定义一个类的局部变量实例而不使用指针和 new,构造函数是在进入函数时调用还是在定义的位置调用?

此类变量具有局部作用域。它们的构造函数在定义时被调用。对于局部静态,构造函数只被调用一次,因为静态将在多次函数调用和返回中存活下来。顺序很重要,就是定义的顺序:

void foo() 
    ....
    if(cond) 
        ...
        // called here: first for f, then for b
        static Foo f;
        static Bar b;
    

    ...
    Foo f; // not static: called here, in every invocation of foo.

如果我在文件中全局定义一个类的另一个实例,在第一次加载可执行文件时会调用该构造函数吗?

是的,据说这样的变量具有静态存储持续时间和命名空间范围。它的构造函数在程序启动时被调用。顺序是它在文件中定义的顺序。也就是说,稍后定义的变量将在稍后调用其 ctor。未定义在不同翻译单元中定义的变量的顺序(注意静态初始化顺序惨败)。但是它们都是在程序启动时调用的。

如果多个线程正在访问 .dll 怎么办?

所有赌注都取消了。该变量仅构造一次。之后,当您启动线程并访问它时,变量必须是线程安全的,或者线程在访问变量时必须进行适当的锁定。

【讨论】:

很抱歉我的静态初始化错误。本地静态非 POD 的构造函数实际上是在控制通过其定义时调用的 - 而不是在进入其块时/之前(仅适用于 POD)。当异常进入游戏时,它变得很重要。干杯 你确定这里bar的构造函数会被调用一次吗? void foo() 静态栏实例;即使在初始构造中多个线程同时到达这里? 只有一个线程才是安全的。如果您有多个线程,则必须确保互斥,以便初始化只发生一次,并且不会发生任何不良情况。 (我回答的最后一部分的意思是,默认情况下不存在线程局部静态这样的东西:只有一个静态对象存在并且线程必须共享该对象)【参考方案3】:

对于 .dll,它取决于编译器和 C 运行时 (CRT)。对于随 Visual Studio 2008 SP1 发布的 MSVC,.dll 的 CRT 将在 DLL_PROCESS_ATTACH 时间初始化全局对象并在 DLL_PROCESS_DETACH 时间销毁它们,假设在 DLL_PROCESS_ATTACH 期间没有发生任何可怕的事情。

【讨论】:

以上是关于什么时候调用构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

什么时候需要显式调用超类构造函数?

构造函数和一般函数异同

为啥执行时没有执行基类的构造函数?

C++学习:4拷贝友元

在使用静态构造函数的时候应该注意几点

C++中,建立子类对象的时候,会调用基类的构造函数,