首页 > 解决方案 > 在类内初始化变量时,我们是否有静态初始化顺序惨败

问题描述

我正在尝试将我们的旧代码从 c++98 重构为 c++14。并且需要使用较旧的 gcc(c++98) 和较新的 gcc(c++14) 进行编译。这就是我们的旧代码的样子(这完全是我们复杂代码的示例。这个类的静态常量在另一个类中使用)。

// BankAccount.h
namespace bank {
class BankAccount {
 public:
    static const unsigned int account_number = 123456789;
    static const double balance = 0.0;
    BankAccount();
    ....
};
}

// BankAccount.cpp
namespace bank {
    BankAccount::BankAccount() {}
    ....
}

看起来从 c++11 开始,只有 ints 和 enums 只允许在类声明中初始化。

问题:通过像上面那样在类声明中初始化静态 const 变量,是否可以避免静态初始化顺序惨败?看起来像上面的代码,我们从来没有观察到这个静态初始化顺序问题,如果我移动静态双精度并浮动到 .cpp 文件,我应该担心这个问题吗?

标签: c++c++14c++98static-initializationstatic-order-fiasco

解决方案


(更新:由于问题已更改为static const成员)

通过声明它们static const,整数变量是安全的。在现代 C++ 中,将它们声明为static constexpr. 语言保证您不会遇到访问未初始化(或更确切地说是零初始化)数值的问题。

对于像 double 这样的浮点数,除非您使用constexpr. 但是,这是 C++98 中没有的功能。如果没有constexpr,您将收到如下编译错误:

// gcc
example.cpp:6:25: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double bank::BankAccount::balance’ of non-integral type [-fpermissive]
    6 |     static const double balance = 0.0;
      |                         ^~~~~~~

或仅具有非标准功能:

// clang with -Wall -std=c++98
example.cpp:6:25: warning: in-class initializer for static data member of type 'const double' is a GNU extension [-Wgnu-static-float-init]
    static const double balance = 0.0;

(旧答案没有声明它们const,但让它们非常量)

你确定这个例子吗?我认为它不会编译(在 C++98 和现代 C++ 中)。除非您将初始化移出类定义,否则您将得到类似的结果:

// gcc
example.cpp:5:30: error: ISO C++ forbids in-class initialization of non-const static member ‘bank::BankAccount::account_number’
    5 |     static unsigned long int account_number = 123456789;
      |                              ^~~~~~~~~~~~~~
example.cpp:6:19: error: ‘constexpr’ needed for in-class initialization of static data member ‘double bank::BankAccount::balance’ of non-integral type [-fpermissive]
    6 |     static double balance = 0.0;
      |                   ^~~~~~~
// clang
example.cpp:5:30: error: non-const static data member must be initialized out of line
    static unsigned long int account_number = 123456789;
                             ^                ~~~~~~~~~
example.cpp:6:19: error: non-const static data member must be initialized out of line
    static double balance = 0.0;
                  ^         ~~~

如果您将其移出,那么您最终可能会以静态初始化顺序惨败告终。这些值将从零初始化开始,然后取决于链接器何时执行真正的初始化代码。

如果可以将变量声明为常量,那将是安全的。


推荐阅读