【问题标题】:why the c++ constructor was not called when it appear as the static member variable?为什么当 c++ 构造函数显示为静态成员变量时没有调用它?
【发布时间】:2013-09-18 09:48:58
【问题描述】:

我遇到了一个奇怪的问题,

在A类中声明一个名为B类的静态成员变量。并在cpp文件中初始化。但是 B 类的构造函数从未被调用过。我尝试使用一些小测试,可以正常调用测试构造函数。所以这对我们的生产系统来说很奇怪。

这样的代码,在hpp中:

class Test
{
    public:
    Test()
    {
        ofstream file("/tmp/wup.txt",ios::app);
        file << "wup in test" << endl;
        file.close();
    }
};

//## An extended personality
class TsdNAExtPersonality : public TsdNAPersonality{
public:

  TsdNAExtPersonality(
        s_gg62_personRec * gg62Header,
                   TsdNAFunctionType requiredFunctionType);
private:
  static Test test;

public:
  TsdNAExtPersonality( string * personalityFile, TsdNAFunctionType requiredFunctionType);
};

在另一个 cpp 文件中,我使用

进行初始化
Test TsdNAExtPersonality::test;

我尝试了几种方法,但我发现所有方法都没有用。

  1. 没有将变量设置为成员变量而是全局变量==>也无法输出
  2. 改变成员变量为指针,改变初始化方式为使用new ==> no

环境为HP-UX,编译为aCC

所以我的问题是:

  1. 是否有任何编译选项会影响变量?也就是说,所有的静态变量都不会被初始化。

  2. 从 C++ 标准来看,它应该在加载库时调用,对吧?

  3. 我用同样的方法放了另一个静态int值,它可以被初始化。但是没有调用类构造函数,很奇怪。

  4. 我的代码有错误吗?

【问题讨论】:

  • SSCCE 如果你不初始化,这里会给出相同的结果。变量。 This SSCCE 确实运行了静态变量的构造函数。
  • 你确定没有调用构造函数吗?你确定这不仅仅是你没有权限去做你想做的事情的问题吗?如果将构造函数中的代码直接放在主函数中会发生什么?
  • @BenjaminLindley 偷了我的评论 - 几乎可以肯定不是构造函数丢失了,而是您无法完成特定的文件操作。您是否检查了 ofstream 对象中的错误[它未在示例中列出]?
  • 请注意,静态变量的构造函数在 main 之前运行,所以如果你希望静态变量的构造函数会对 main 中创建的对象的状态产生一些影响,它不会像这样发生那个。
  • @BenjaminLindley 我确定没有调用构造函数,因为我设置了另一个变量,例如 i = 4,我发现 i 仍然是 0。

标签: c++ unix static constructor acc


【解决方案1】:

从 C++ 的标准来看,它应该在加载库时调用,对吧?

没有。具有静态存储持续时间的对象的动态初始化保证在执行同一翻译单元中定义的任何函数之前发生。如果没有这样的函数,或者你的程序从不调用它们,那么就不能保证它会被初始化。

我用同样的方法放了另一个静态int值,它可以被初始化。但是没有调用类构造函数,很奇怪。

int 变量在程序启动之前被静态初始化,只要它的初始化器是常量。

是否有任何编译选项会影响变量?

我不知道,但我不熟悉你们的平台。您可以通过在函数中确定对象的范围来让自己更好地控制对象的创建:

static Test & test() {
    static Test test;
    return test;
}

现在保证在第一次调用函数时被初始化。当然,您需要记住在某个时候调用它。

【讨论】:

  • 我没有将它放入方法中,因为我将读取文件内容,这将花费时间。所以我想在加载库时进行初始化。
  • 由于我没有找到最佳解决方案,我更改了代码并将变量放入函数中,然后按我的预期正常初始化。
【解决方案2】:

C++ 中的静态初始化是:

  • 零初始化
  • 不断初始化
  • 动态初始化

因此您最好的选择是在第一次函数调用时进行初始化:

int fn() {
    static int result = 42;
    return result;
}

编辑

如果要在main之前初始化:

struct Initialize { 
    Initialize() { fn(); }
}

Initialize initialize;

【讨论】:

  • 谢谢,但我需要加快速度,因为我想在构造函数中读取一些文件,这将花费几秒钟。如果我投入该功能,生产系统将受到影响。
【解决方案3】:

C++ 程序的启动和关闭有点像灰色区域,因为不清楚您已经可以使用多少代码(因为它已被初始化)以及还有多少代码正在启动。在关闭时,析构函数也会发生同样的情况......当您的静态实例被销毁时,尚不清楚有多少子系统已经关闭。

此外,您永远不应该对任何可能失败的东西使用静态初始化,在main 开始之前或结束之后进行调试可能非常困难。

另请注意,未定义初始化静态的顺序(除了相对于同一编译单元中的其他静态),它可能会从一个编译更改为下一个编译。这意味着您可能会对工作中的程序感到满意,直到由于某种奇怪的原因您得到不同的初始化顺序并且事情停止工作而无需对代码进行任何相关更改。

对极其简单的事情使用静态初始化是可以的,因为其他任何事情都不是,您应该改为进行适当的受控初始化。

【讨论】:

  • 只需在main中以受控顺序显式初始化子系统,并在退出时有序关闭它们。使用隐式或惰性构造似乎是一种不错的方法,它可能适用于简单的情况......如果项目增长,但它是一个可能会严重反击的模型。
【解决方案4】:

我认为您的编译器存在错误。

在 linux/g++ 上运行这个简单的代码会得到预期的结果:

#include <iostream>

using namespace std;

class A
{
    public:
        A() { cout << "Hallo" << endl; }
};

class B
{
    public:
    static A a;
};

A B::a;    // < here the constructor must be called!

int main()
{
   cout << "Main runs" << endl;
   return 0;
}

结果:

Hallo
Main runs

构造静态数据成员时必须调用构造函数(上面的注释行)。

【讨论】:

  • 是的,我也做了同样的测试。构造函数被正常调用。
猜你喜欢
  • 2011-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-19
  • 1970-01-01
  • 2011-10-09
  • 1970-01-01
  • 2011-10-21
相关资源
最近更新 更多