与 Java 静态块等效的 C++ 习语是什么?
我有一个包含一些静态成员的类,我想运行一些代码来初始化它们(假设这段代码不能转换为简单的表达式).在 Java 中,我会这样做
I have a class with some static members, and I want to run some code to initialize them (suppose this code cannot be converted into a simple expression). In Java, I would just do
class MyClass {
static int myDatum;
static {
/* do some computation which sets myDatum */
}
}
除非我弄错了,C++ 不允许这样的静态代码块,对吧?我应该怎么做?
Unless I'm mistaken, C++ does not allow for such static code blocks, right? What should I be doing instead?
我想要以下两个选项的解决方案:
I would like solution for both of the following options:
- 在加载进程时(或加载具有此类的 DLL)时发生初始化.
- 在第一次实例化类时进行初始化.
对于第二个选项,我在想:
For the second option, I was thinking of:
class StaticInitialized {
static bool staticsInitialized = false;
virtual void initializeStatics();
StaticInitialized() {
if (!staticsInitialized) {
initializeStatics();
staticsInitialized = true;
}
}
};
class MyClass : private StaticInitialized {
static int myDatum;
void initializeStatics() {
/* computation which sets myDatum */
}
};
但这是不可能的,因为 C++(目前?)不允许初始化非常量静态成员.但是,至少这将静态块的问题减少到通过表达式进行静态初始化的问题......
but that's not possible, since C++ (at the moment?) does not allow initialization of non-const static members. But, at least that reduces the problem of a static block to that of static initialization by expression...
推荐答案
您也可以在 C++ 中拥有静态块 - 外部类.
事实证明,我们可以实现 Java 风格的静态块,尽管是在类外部而不是在类内部,即在翻译单元范围内.该实现在底层有点丑陋,但使用时却非常优雅!
You can have static blocks in C++ as well - outside classes.
It turns out we can implement a Java-style static block, albeit outside of a class rather than inside it, i.e. at translation unit scope. The implementation is a bit ugly under the hood, but when used it's quite elegant!
现在有一个 GitHub repo 用于解决方案,其中包含一个头文件:static_block.hpp
.
There's now a GitHub repo for the solution, containing a single header file: static_block.hpp
.
如果你写:
static_block {
std::cout << "Hello static block world!
";
}
此代码将在您的 main()
之前运行.你可以初始化静态变量或做任何你喜欢的事情.所以你可以在你的类的 .cpp
实现文件中放置这样一个块.
this code will run before your main()
. And you can initialize static variables or do whatever else you like. So you can place such a block in your class' .cpp
implementation file.
注意事项:
- 您必须用花括号将静态块代码括起来.
- 静态代码的相对执行顺序是在C++中不保证不保证一个>.
- You must surround your static block code with curly braces.
- The relative order of execution of static code is not guaranteed in C++.
静态块实现涉及使用函数静态初始化的虚拟变量.您的静态块实际上是该函数的主体.为了确保我们不会与其他一些虚拟变量(例如来自另一个静态块 - 或其他任何地方)发生冲突,我们需要一些宏机制.
The static block implementation involves a dummy variable initialized statically with a function. Your static block is actually the body of that function. To ensure we don't collide with some other dummy variable (e.g. from another static block - or anywhere else), we need a bit of macro machinery.
#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
#ifdef __COUNTER__
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__)
#else
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)
#endif // __COUNTER__
#ifdef _MSC_VER
#define _UNUSED
#else
#define _UNUSED __attribute((unused))
#endif // _MSC_VER
这里是把东西放在一起的宏观工作:
and here is the macro work to put things together:
#define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_))
#define STATIC_BLOCK_IMPL1(prefix)
STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var))
#define STATIC_BLOCK_IMPL2(function_name,var_name)
static void function_name();
static int var_name _UNUSED = (function_name(), 0) ;
static void function_name()
注意事项:
- 一些编译器不支持
__COUNTER__
- 它不是 C++ 标准的一部分;在这些情况下,上面的代码使用__LINE__
,它也可以.GCC 和 Clang 确实支持__COUNTER__
. - 这是C++98;您不需要任何 C++11/14/17 构造.但是,它不是有效的 C,尽管没有使用任何类或方法.
- 如果您的 C++11 编译器不喜欢GCC 风格的未使用扩展.
- 这不会避免或帮助解决 静态初始化订单惨败,因为虽然您知道您的静态块将在
main()
之前执行,但您无法保证相对于其他静态初始化何时发生这种情况.
- Some compilers do not support
__COUNTER__
- it's not part of the C++ standard; in those cases the code above uses__LINE__
, which works too. GCC and Clang do support__COUNTER__
. - This is C++98; you don't need any C++11/14/17 constructs. However, it's not valid C, despite not using any classes or methods.
- The
__attribute ((unused))
might be dropped, or replaced with[[unused]]
if you have a C++11 compiler which doesn't like the GCC-style unused extension. - This does not avert or help with the static initialization order fiasco, since while you know your static block will execute before
main()
, you are not guaranteed when exactly that happens relative to other static initializations.
现场演示
相关文章