我有一些代码,必须通过相当多的代码来设置全局资源:
globalClass foo; // global variable / object; give it a memory space to live
void doSomething( void )
{
foo.bar(); // use the global foo object
}
int main( int argc, const char *argv[] )
{
foo( argc ); // foo can only be instantiated in main as it's using
// information that's only available here
doSomething(); // use the global foo object
return 0;
}
如您所见,
foo
具有全局范围 - 但要调用其构造函数,我需要一些仅在main
内部可用的信息。
我怎样才能做到这一点?
我能想到的唯一解决方案是使
foo
成为指向 globalClass
的指针 - 但这会导致每次我使用 foo
时指针取消引用。在紧密循环中使用时,这可能会产生性能问题...
PS:在真实的程序中,
main
和doSomething
将存在于不同的文件中。当然可以保证 foo
在实例化之前不会被访问。
将
foo
作为函数内的 static
变量怎么样?这样,它仅在调用函数时才会被实例化:
globalClass& getThing()
{
static globalClass thing;
return thing;
}
void doSomething(const globalClass& thing);
int main()
{
const globalClass& x = getThing();
doSomething(x);
}
正如您提到的,使用指针是最简单、最干净的事情。 指针取消引用的开销实际上并没有那么多。 我建议使用它,除非您确实证明了开销是显而易见的。
您的第二个选择是将
globalClass
的构造和初始化分为两个单独的方法。 构造函数只会做不需要外部信息的最简单的事情,并且您可以调用 init(argc)
或 main
内部的任何内容来合并外部信息。
您还可以使用赋值来初始化 foo,例如:
globalClass foo;
int main(int argc, const char *argv[]) {
globalClass bar(argc);
foo = bar;
}
本质上是使用临时变量进行初始化,然后复制结果。
如果您不想间接且不介意自己进行清理,那么这是一个非常糟糕的黑客:
union ClassHolder
{
globalClass x;
char buf[sizeof globalClass];
constexpr ClassHolder() noexcept : buf() { }
};
ClassHolder h;
globalClass & foo = h.x;
int main()
{
new (static_cast<void *>(&h.x)) globalClass(arg1, arg2, arg3);
// main program
h.x.~globalClass();
}
#define GLOBAL_VARIABLE(type, var) \
inline char _##var [ sizeof(type) ]; \
inline type &var = reinterpret_cast<type &>( _##var );
GLOBAL_VARIABLE(globalClass, foo)
这将生成
inline char _foo [ sizeof(globalClass) ];
inline globalClass &foo = reinterpret_cast<globalClass &>( _foo );
现在分配内存但不初始化。该变量尚未准备好使用。您可以使用
std::construct_at
来构造 foo
。
你可以这样做:
globalClass* foo;
// declare foo as a global pointer to class globalClass. No object instantiated here
void doSomething( void )
{
foo->bar(); // use the global foo object pointer
}
int main( int argc, const char *argv[] )
{
foo = new globalClass();
// an object is instantiated from class globalClass and the pointer to that object assigned to foo. This object will not be destroyed when the function who created ends. Parameters for the constructor can the passed inside the ()
doSomething(); // use the global foo object
return 0;
}