假设我有一个类,其唯一目的是在构造对象时产生的副作用(例如,使用工厂注册类):
class SideEffectCauser {
public:
SideEffectCauser() { /* code causing side-effects */ }
};
另外假设我想让一个对象为每个翻译单元创建一次这样的副作用。对于每个这样的翻译单元,我希望能够在.cpp文件中的命名空间范围内放置一个SideEffectCauser
对象,例如,
SideEffectCauser dummyGlobal;
但是C ++ 03标准的3.6.2 / 3建议除非使用.cpp文件中的对象或函数,以及this和在线等文章,否则不需要构造此对象诸如this之类的讨论表明这些对象有时不会被初始化。
另一方面,Is there a way to instantiate objects from a string holding their class name? 有一个声称可行的解决方案,我注意到它基于使用像SideEffectCauser
这样的类型的对象作为静态数据成员,而不是全球,例如,
class Holder {
static SideEffectHolder dummyInClass;
};
SideEffectHolder Holder::dummyInClass;
dummyGlobal
和dummyInClass
都是非本地静态,但仔细研究C ++ 03标准的3.6.2 / 3表明该段落仅适用于命名空间范围内的对象。我实际上无法在C ++ 03标准中找到任何内容,即当类范围内的非局部静态动态被动态初始化时,尽管9.4.2 / 7表明相同的规则适用于它们在命名空间中的非局部静态范围。
问题1:在C ++ 03中,有没有理由相信dummyInClass
比dummyGlobal
更有可能被初始化?如果没有使用同一翻译单元中的任何功能或对象,或者两者都可以未初始化?
问题2:C ++ 11中有什么变化吗? 3.6.2和9.4.2中的措辞与C ++ 03版本不同,但据我所知,上面描述的场景没有规定行为差异。
问题3:是否有可靠的方法在函数体外部使用类SideEffectHolder
之类的对象来强制发生副作用?
答案 0 :(得分:1)
我认为唯一可靠的解决方案是为特定的编译器和运行时设计它。没有标准涵盖共享库中全局变量的初始化,我认为这是最复杂的情况,因为这很大程度上取决于加载器,因此依赖于操作系统。
Q1:不 Q2:没有任何实际意义 问题3:不是标准的方式
答案 1 :(得分:0)
我在Linux下使用与g ++ / C ++ 11类似的东西,并按预期注册我的工厂。我不确定为什么你不会得到调用的函数。如果要实现所描述的内容,则意味着该单元中的每个函数都必须调用初始化函数。我不太清楚如何做到这一点。我的工厂也位于命名空间内,尽管它名为命名空间。但我不明白为什么不会被召唤。
namespace snap {
namespace plugin_name {
class plugin_name_factory {
public:
plugin_name_factory() { plugin_register(this, name); }
...
} g_plugin_name_factory;
}
}
请注意,无论如何都不应该在C ++中使用static关键字。静态定义通常比全局定义慢。