28

假设我有一个类,其唯一目的是在构造其对象期间引起的副作用(例如,向工厂注册一个类):

class SideEffectCauser {
public:
  SideEffectCauser() { /* code causing side-effects */ }
};

还假设我想让一个对象为几个翻译单元中的每一个创建一次这样的副作用。对于每个这样的翻译单元,我希望能够SideEffectCauser在 .cpp 文件的命名空间范围内放置一个对象,例如,

SideEffectCauser dummyGlobal;

但是 C++03 标准的 3.6.2/3 建议根本不需要构造该对象,除非使用 .cpp 文件中的对象或函数,并且诸如此类的文章和诸如此类的在线讨论表明此类对象有时未初始化。

另一方面,有没有办法从保存类名的字符串中实例化对象?有一个声称可以工作的解决方案,我注意到它是基于使用类型的对象SideEffectCauser作为静态数据成员,而不是作为全局对象,例如,

class Holder {
  static SideEffectHolder dummyInClass;
};

SideEffectHolder Holder::dummyInClass;

两者dummyGlobaldummyInClass都是非局部静态,但仔细查看 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在函数体外部)来强制发生副作用?

4

2 回答 2

1

我认为唯一可靠的解决方案是为特定的编译器和运行时设计它。没有标准涵盖共享库中全局变量的初始化,我认为这是最复杂的情​​况,因为这在很大程度上取决于加载程序,因此也取决于操作系统。

Q1:没有 Q2:没有任何实际意义 Q3:没有标准的方式

于 2012-12-31T11:16:51.190 回答
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 关键字。静态定义通常比全局定义要慢。

于 2012-12-13T10:02:17.997 回答