什么';这是C++;与Java静态块等效的惯用语?
我有一个包含一些静态成员的类,我想运行一些代码来初始化它们(假设此代码无法转换为简单表达式)。在Java中,我只需要什么';这是C++;与Java静态块等效的惯用语?,java,c++,initialization,equivalent,static-block,Java,C++,Initialization,Equivalent,Static Block,我有一个包含一些静态成员的类,我想运行一些代码来初始化它们(假设此代码无法转换为简单表达式)。在Java中,我只需要 class MyClass { static int myDatum; static { /* do some computation which sets myDatum */ } } 除非我错了,C++不允许使用这样的静态代码块,对吗?我该怎么做呢 我希望为以下两个选项提供解决方案: 在加载进程(或加载带有此类的DLL)时发生初始化
class MyClass {
static int myDatum;
static {
/* do some computation which sets myDatum */
}
}
除非我错了,C++不允许使用这样的静态代码块,对吗?我该怎么做呢
我希望为以下两个选项提供解决方案: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++(现在)不允许初始化非静态静态成员。但是,至少这将静态块的问题减少为通过表达式进行静态初始化的问题…您可以在C++中初始化静态数据成员:
#include "Bar.h"
Bar make_a_bar();
struct Foo
{
static Bar bar;
};
Bar Foo::bar = make_a_bar();
您可能需要考虑翻译单元之间的依赖关系,但这是一般的方法。对于#1,如果您确实需要在流程启动/库加载时进行初始化,则必须使用特定于平台的工具(例如Windows上的DllMain)
但是,如果在执行与static相同的.cpp文件中的任何代码之前运行初始化就足够了,那么以下操作应该有效:
// Header:
class MyClass
{
static int myDatum;
static int initDatum();
};
这样,保证在执行.cpp
文件中的任何代码之前调用initDatum()
如果不想污染类定义,还可以使用(C++11):
别忘了最后一对括号——它实际上调用lambda
至于#2,有一个问题:不能在构造函数中调用虚函数。最好在类中手动执行此操作,而不是使用基类:
class MyClass
{
static int myDatum;
MyClass() {
static bool onlyOnce = []() -> bool {
MyClass::myDatum = /*whatever*/;
return true;
}
}
};
假设这个类只有一个构造函数,那么就可以了;它是线程安全的,因为C++ 11保证了初始化静态局部变量的安全性。 C++中可以有静态块,也可以有外部类。
事实证明,我们可以实现一个Java风格的静态块,尽管是在类之外而不是在类内部,即在翻译单元范围内。在引擎盖下的实现有点难看,但使用时相当优雅
可下载版本
现在,该解决方案有一个包含单个头文件的
用法
如果你写:
static_block {
std::cout << "Hello static block world!\n";
}
以下是宏观工作,以将事物组合在一起:
#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 __attribute((unused)) = (function_name(), 0) ; \
static void function_name()
注意事项:
- 一些编译器不支持< C++ >代码> >代码>这不是C++标准的一部分;在这些情况下,上面的代码使用
,这同样有效。GCC和Clang确实支持\uuuuuuuuuuuuuuuuuuuuuuuuuuuu
\uuuuu计数器\uuuuuu
- 这是C++98;您不需要任何C++11/14/17构造。然而,尽管没有使用任何类或方法,它仍然不是有效的C
- 如果您的C++11编译器不喜欢GCC风格的未使用扩展,则可以删除
,或者将其替换为\u属性((未使用))
[[unused]]
- 这并不能避免或有助于,因为虽然您知道静态块将在
之前执行,但相对于其他静态初始化,您不能保证在什么时候执行main()
你最好采取完全不同的方法。静态信息的集合实际上需要在StaticInitialized内部定义吗 考虑创建一个单独的名为SharedData的单例类。然后,调用SharedData::Instance()的第一个客户端将触发共享数据集合的创建,这些数据将只是普通类数据,尽管它们位于静态分配的单个对象实例中: //SharedData.h
class SharedData
{
public:
int m_Status;
bool m_Active;
static SharedData& instance();
private:
SharedData();
}
//SharedData.cpp
SharedData::SharedData()
: m_Status( 0 ), m_Active( true )
{}
// static
SharedData& SharedData::instance()
{
static SharedData s_Instance;
return s_Instance;
}
任何对共享数据集合感兴趣的客户机现在都必须通过SharedData单例访问它,第一个调用SharedData::instance()的此类客户机将在SharedData的ctor中触发该数据的设置,该数据只会被调用一次
现在,您的代码表明不同的子类可能有自己的初始化静态数据的方法(通过initializeStatics()的多态性)。但这似乎是一个相当有问题的想法。多个派生类是否真的打算共享一组静态数据,但每个子类的初始化方式不同?这仅仅意味着,无论哪个类首先被构造,都将以自己的狭隘方式设置静态数据,然后其他所有类都必须使用此设置。这真的是你想要的吗
我也有点困惑,为什么要尝试将多态性与私有继承相结合。您真正希望使用私有继承(而不是组合)的案例数量非常少。我想知道您是否认为需要initializeStatics()是虚拟的,以便派生类能够调用它。(事实并非如此)但您似乎确实希望重写派生类中的initializeStatics(),原因我不清楚(请参阅前面的内容)。整个设置似乎有些奇怪。下面是一个使用C++11模拟
静态块的好方法:
宏
定义CONCATE(X,Y)X#Y
#定义CONCATE(X,Y)CONCATE_ux(X,Y)
#定义唯一(名称)CONCATE(名称,行)
结构静态
{
模板静态_uT(仅_一次){仅_一次();}
~Static_(){}//以计数器“警告:未使用的变量”
};
//如果我们希望函数中有多个'static'块,则需要'UNIQUE'宏
#定义静态uuUnique(块)=[&]()->void
用法
void foo()
{
STD::C++中的CUT没有这样的成语。
原因在于从C++生成的代码的性质完全不同:运行时不是“托管”的。在编译后生成的代码中,不再存在“类”的概念,并且
#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__
#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 __attribute((unused)) = (function_name(), 0) ; \
static void function_name()
class SharedData
{
public:
int m_Status;
bool m_Active;
static SharedData& instance();
private:
SharedData();
}
SharedData::SharedData()
: m_Status( 0 ), m_Active( true )
{}
// static
SharedData& SharedData::instance()
{
static SharedData s_Instance;
return s_Instance;
}
#define CONCATE_(X,Y) X##Y
#define CONCATE(X,Y) CONCATE_(X,Y)
#define UNIQUE(NAME) CONCATE(NAME, __LINE__)
struct Static_
{
template<typename T> Static_ (T only_once) { only_once(); }
~Static_ () {} // to counter "warning: unused variable"
};
// `UNIQUE` macro required if we expect multiple `static` blocks in function
#define STATIC static Static_ UNIQUE(block) = [&]() -> void
void foo ()
{
std::cout << "foo()\n";
STATIC
{
std::cout << "Executes only once\n";
};
}
#define M_CON(A, B) M_CON_(A, B)
#define M_CON_(A, B) A##B
#define STATIC_BLOCK \
[[maybe_unused]] static const auto M_CON(_static_block,__LINE__) = []()
#include <iostream>
#include "static.hpp"
STATIC_BLOCK {
std::cout << "my static block" << '\n';
int A,B,C,D = 12;
std::cout << "my static block with " << A << '\n';
return 0; // this return is must
}();
int main(){
std::cout << "in main function\n";
}