初始化与类类型相同的静态成员(静态初始化顺序问题)
Initialization of static member with same type as class (static initialization order problem)
>假设我有一个类Super
,其中我有一个类型为Super
的静态成员,它只是定义了Super
的常用实例
// super.hpp
class Super
{
public:
Super(const double a):
m_a(a)
{}
double a() const { return m_a; }
static const Super thing; // use this a lot in code
private:
double m_a;
};
与实施
// super.cpp
#include "super.hpp"
const Super Super::thing = Super(1.0); // definition
在这一点上,我认为一切都很好,但如果不是,请纠正我。
现在我也有Super
的子类,具有类似的静态成员
// sub.hpp
#include "super.hpp"
class Sub : public Super
{
public:
Sub(const double a):
Super(a)
{}
explicit Sub(const Super& obj):
Super(obj)
{}
static const Sub thing;
};
与实施
// sub.hpp
#include "sub.hpp"
const Sub Sub::thing = Sub(Super::thing); // WORKS IN MYSTERIOUS WAYS
最后是一个用法示例
// main.cpp
#include <iostream>
#include "sub.hpp"
int main()
{
Super super = Super::thing;
std::cout << super.a() << std::endl;
Sub sub = Sub::thing;
std::cout << sub.a() << std::endl;
}
当我使用以下设置编译它时
// CMakeLists.txt
project (hello)
add_executable(hello main.cpp super.cpp sup.cpp)
我得到了预期的输出
$ ./hello
1
1
但是如果我在CMakeLists
中更改 cpp 文件的顺序(sub.cpp
在super.cpp
之前
// CMakeLists.txt
project (hello)
add_executable(hello main.cpp sup.cpp super.cpp)
我得到
$ ./hello
1
0
我认为这是静态初始化顺序"惨败"(?(的一个例子,我对它发生的原因有一些了解。
所以问题变成了:有没有办法获得有关未初始化静态的警告,或者有任何方法可以避免这个问题?
我已经阅读了如何防止"静态初始化顺序问题"?,但我希望能够保留Sub::thing
接口,并避免将其替换为Sub::thing()
。
根据您的评论,我做了以下工作:
- 使构造函数
constexpr
static
成员constexpr inline
(您必须将它们放入头文件中,而不是.cpp
(,因此需要 C++17
现在,您的静态变量已constexpr
,因此它们将被静态初始化,因此静态初始化顺序的惨败不会对它们发生。
所以,这个解决方案对我有用:
class Super
{
public:
constexpr Super(const double a):
m_a(a)
{}
double a() const { return m_a; }
static const Super thing;
private:
double m_a;
};
constexpr inline Super Super::thing = Super(1.0);
class Sub : public Super
{
public:
constexpr Sub(const double a):
Super(a)
{}
constexpr explicit Sub(const Super& obj):
Super(obj)
{}
static const Sub thing;
};
constexpr inline Sub Sub::thing = Sub(Super::thing);
#include <iostream>
int main()
{
Super super = Super::thing;
std::cout << super.a() << std::endl;
Sub sub = Sub::thing;
std::cout << sub.a() << std::endl;
}
有没有办法得到关于未初始化的静态的警告,
我不知道
或者有什么方法可以避免这个问题?
-
您可以避免全局成员,并使用延迟初始化将全局包装在函数中,因此更改:
// header class Super { static const Super thing; // ... }; // cpp file const Super Super::thing = Super(1.0); // definition
自
// header class Super { static const Super& thing(); // ... }; // cpp file const Super& Super::thing() { static const Super instance{1.0}; return instance; }
和类似
class Sub : public Super { public: // ... static const Sub thing; }; // sub.cpp const Sub Sub::thing = Sub(Super::thing);
由
class Sub : public Super { public: // ... static const Sub& thing(); }; // sub.cpp const Sub& Sub::thing() { static const Sub instance(Super::thing()); return instance; }
-
或者将所有全局放在一个翻译单元中,因为顺序是有保证的。
// global.cpp #include "super.hpp" #include "sub.hpp" const Super Super::thing = Super(1.0); // Defined in order const Sub Sub::thing = Sub(Super::thing); // so you have control
相关文章:
- 从另一个静态常量数组初始化静态常量数组(只需少量计算)
- "local scope"中的 C++ 初始化静态变量
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 未调用的初始化静态thread_local结构的构造函数和析构函数
- 如何在 C++ 中使用 NULL(或 0)初始化静态字符数组
- 如何从静态类函数初始化静态类对象
- C++:用IIFE线程初始化静态局部变量安全吗
- 如何在 c++ 中初始化静态类对象?
- 使用 lambda 初始化静态数组
- 使用 lambda 函数初始化静态数据成员
- 如何从 std::integer_sequence 初始化静态数组?
- 在构造函数中初始化静态函数指针
- C - 初始化静态成员的方法
- 大括号使用枚举类初始化静态常量unordered_map
- C++ main 函数中初始化静态变量
- 在定义(.cpp文件)中初始化静态浮点 constexpr 成员是可能的
- 错误 C2864:'element::next':只能在类 (STRUCT) 中初始化静态常量整数数据成员
- 我应该使用类内发起器初始化静态常量数据成员还是在其类外的定义中初始化静态常量数据成员
- 如何在运行时使用静态成员函数初始化静态成员变量
- 与其他静态const成员初始化静态常量成员