有一次我读了一个很棒的C++常见问题解答(它真的很好!!),并阅读了关于如何防止静态初始化顺序"惨败"的主题。因此,作者建议将静态变量包装成函数,从而通过保持变量的创建顺序来防止"惨败"。但在我看来,这似乎是一个粗鲁的变通方法。所以我的问题是,除了把"静态的东西"包装成函数之外,还有什么现代的、更面向模式的方法可以防止这种"惨败"吗???
现代的、更面向模式的方法是首先不要使用全局变量
没有其他办法了。
否则,这不会是一场"惨败"!
所以我的问题是,除了将"静态的东西"封装到函数中之外,还有什么现代的、更面向模式的方法可以防止这种"惨败"吗???
在大多数情况下,您可以在主函数中声明您的"全局"数据,并在需要时使用依赖项注入来传递它。换句话说,根本没有静态。
在实践中,您可能会遇到需要静态数据的情况。如果不存在对其他静态的依赖关系,则将静态数据设为const/constexpr
。
// smart pointer that implements the "Foo" release policy
class FooPointer
{
static const FooPointer NullFoo; // does not depend on other static values
/* ... */
};
如果静态变量确实相互依赖,只需将它们封装在静态函数中即可:
// smart pointer that implements the "Foo" release policy
class FooPointer
{
static const FooPointer& NullFoo(); // depends on other static values
/* ... */
};
总结:
大多数(90%?99%?)静态/全局/共享数据应该被依赖性注入到使用位置,而不是创建为静态数据。
在极少数情况下,当出于某种原因需要静态,并且它们不依赖于其他静态时,请声明静态变量。
在非常的罕见情况下,当静态需要是静态的并且它们相互依赖时,请在静态方法中交换它们。
根据经验,如果你有很多第二种和第三种情况,那么你对第一种情况做得不够。
解决这个问题的更常见的方法是尽可能避免静态,在依赖构造顺序的对象之间更是如此。
然后按所需顺序构造对象。例如,如果我们有两个对象x和y,并且如果x没有被构造,y的构造将失败,那么首先构造x,并将其提供给y的构造函数(或另一个成员)
SomeObject x;
SomeOtherObject y(x);
或
SomeObject *x = new SomeObject;
SomeOtherObject y = new SomeObject(*x);
(以上两者都假设y
的构造函数需要引用)。
如果需要在函数之间共享x
和y
,只需将它们作为参数传递给函数即可。
如果必须使用statics(即,您不希望到处都键入传递参数),则将statics设置为指针,并初始化它们一次(例如,在main()
中)。
// all source files can use x and y via these declarations (e.g. via a header file)
extern SomeObject *x;
extern SomeOtherObject *y;
// definition in one source file only
SomeObject *x;
SomeOtherObject *y;
int main()
{
x = new SomeObject;
y = new SomeOtherObject(*x);
// call other functions that use x and y.
delete y;
delete x;
}
但是,实际上,如果可能的话,最好避免使用静力学。
这不是一个确切的答案,但我引用了使用C++20 中constinit
功能的cppstores中的有用技巧
constnit强制静态或线程本地的持续初始化变量。它可以通过以下方式帮助限制静态订单初始化失败使用预编译的值和定义良好的顺序,而不是动态初始化和链接顺序…
#include <array>
// init at compile time
constexpr int compute(int v) { return v*v*v; }
constinit int global = compute(10);
// won't work:
// constinit int another = global;
int main() {
// but allow to change later...
global = 100;
// global is not constant!
// std::array<int, global> arr;
}