C++ c++;全局变量的后期实例化
我有一些代码,其中必须通过相当多的代码设置全局资源:C++ c++;全局变量的后期实例化,c++,c++11,C++,C++11,我有一些代码,其中必须通过相当多的代码设置全局资源: 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
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
作为函数中的静态变量如何?这样,它只有在调用函数时才会被实例化:
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();
}
联合类持有者
{
全局类x;
char buf[全局类的大小];
constexpr ClassHolder()noexcept:buf(){}
};
类别持有人h;
globalClass&foo=h.x;
int main()
{
新的(静态_cast(&h.x))全局类(arg1、arg2、arg3);
//主程序
h、 x.~globalClass();
}
使其成为一个全局函数,返回对静态局部的引用,会不会有那么多的语法负担?如果是这样,如果你已经习惯了全局变量的“邪恶”,为什么不再忍受一个邪恶,只给globalClass
一个init
函数而不是依赖构造函数呢?为什么它必须是一个全局变量,而不是doSomething
的参数呢?语法负担对我来说是可以的,只要它停留在编译时或者安装时(即运行时的第一次迭代)。init
的想法很好,但很抱歉,我忘了注意到globalClass
来自一个我并不急于修改的外部库。(顺便说一句:当然,globals被认为是邪恶的——但在像这里这样的受控环境中,对于我来说,这是一个不错的选择,而不是在每个实例中存储一个globalClass
的副本doSomething
,这实际上是一个类的方法…)globals只有在没有正确编码的情况下才是邪恶的。但是如果您想避免它们,可以在main
中创建并初始化对象,并将指向该对象的指针/引用传递给需要访问它的所有函数。您不能调用foo
的构造函数。您可以调用globalClass
的构造函数来创建它的实例。在您的main
中,您正在foo
中调用globalClass::operator()
,这是一个globalClass
实例。+1,此方法还可以防止我处理重线程代码。我们不使用函数static,因为如果两个线程同时进入函数,则无法保证函数static只构造一次。@Brian,我认为这是有保证的。但是如果你想确定,在对象构造完成后,从nmain启动线程,并将其传递给其他人。不过,这很尴尬,因为你需要对象是默认的可构造和可分配的……这个例子没有显示如何像OP ask一样,由argc
在main
中初始化globalClass
,常量引用也不会让你这么做。@LightnessRacesinOrbit:我想把它称为“联合黑客”:-)好了:P尽管实际上我想知道buf
的初始化是否算作写入…@LightnessRacesinOrbit:那没关系,因为我们以后会覆盖它。@LightnessRacesinOrbit:嘿,难道没有一个子句表明指向任何工会成员的指针是相同的吗?也许我的原始版本还可以…不,因为你仍然在写buf
,然后从x
读取。也许吧。这是一个不错的解决方案,但有时它不起作用:您需要一个默认构造函数和赋值运算符(或复制运算符)。如果globalClass
没有这些,它将无法工作。但在许多情况下,这是一个很好的解决方案,在安装期间只会产生一点开销,但在运行期间是免费的。