c++ - 在类内初始化变量时,我们是否有静态初始化顺序惨败
问题描述
我正在尝试将我们的旧代码从 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 文件,我应该担心这个问题吗?
解决方案
(更新:由于问题已更改为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;
^ ~~~
如果您将其移出,那么您最终可能会以静态初始化顺序惨败告终。这些值将从零初始化开始,然后取决于链接器何时执行真正的初始化代码。
如果可以将变量声明为常量,那将是安全的。
推荐阅读
- asp.net-web-api - 无法在 Visual Studio 2019 中添加 wep.api 控制器
- php - 其他产品页面的重复值不断删除
- firebase - 在 Firebase 身份验证中,“最近”经过身份验证意味着多久以前?
- c# - 从 ASP.NET 应用程序通过 Google API 发送电子邮件
- python - Python:Pandas Grouper() 函数时间戳选择
- google-cloud-platform - Google Cloud Endpoint:如何显示示例响应、yaml 配置
- android - MutableLiveData 的变化在显式设置值之前反映在观察者中
- css - 如何在箭头相互重叠的地方制作css?
- r - R中的TSP,具有给定的距离
- elasticsearch - Elasticsearch 自动完成功能无法正常工作