【发布时间】:2012-12-05 02:02:16
【问题描述】:
假设我有一个类,其唯一目的是在构造其对象期间产生副作用(例如,向工厂注册一个类):
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 之类的对象来强制产生副作用?
【问题讨论】:
-
我想我们前段时间讨论过这个问题,C++03 和 C++11 都没有严格要求如果 TU 中没有函数被调用,则必须构造静态,但没有编译器会利用它因为它会破坏每个人的代码......
-
回答你的第一个问题:在 C++03 中,Schwarz counter 将保证静态类
dummyInClass和dummyGlobal被初始化,无论它们的对象是否被调用。这种方法消除了与初始化或不存在相关的任何不确定性。 -
@KerrekSB:不幸的是,我的问题是由一位同事的经验提出的,他发现静态链接一切正常,但动态链接却不行。有人会想,当通过动态链接引入 TU 时,该 TU 中的非本地静态变量将被动态初始化,但这似乎没有发生,因为该 TU 中没有使用任何内容(并且不会直到非局部静力学产生副作用)。
-
+1 提出了一个很好的问题,但这样做的目的是可疑的。这意味着仅仅链接到目标文件会导致应用程序的行为发生变化,即使应用程序会在没有目标文件的情况下进行链接。
-
@Jan :与 C++03 不同,在 C++11 中,未命名命名空间中的函数具有内部链接,除非另有说明。