具有静态成员的类,包含C ++中的静态成员

时间:2012-11-24 16:51:48

标签: c++ static destruction

我有一个包含静态成员'obj'的类。静态类成员obj本身包含一个静态成员(恰好是类的互斥类型)。

现在,当我的程序终止时,它会崩溃。当静态对象'obj'被破坏时会发生这种情况。 'obj'的析构函数调用它的静态成员(我自己的互斥体类型遵循RAII惯用法来破坏底层的低级对象)。不幸的是,由于静态对象的初始化顺序( - >相反的析构函数顺序)未定义,因此该成员恰好被销毁了。

如何干净利落地生存?我被高估了这种情况并没有经常发生。看起来一般来说静态非POD成员是非常危险的。特别是如果你不清楚他们的内心结构。

3 个答案:

答案 0 :(得分:0)

如果你在函数内部使它们static,那么你将根据谁先调用函数来命令它们的生命周期。这就是单身人士倾向于实施的方式。

foo& get_foo() {
  static foo instance;
  return instance;
}

bar& get_bar() {
  static bar instance;
  return instance;
}

你最好避免使用静力学。

答案 1 :(得分:0)

当试图避免动态分配时,这是一个常见的问题。

我避免这个问题的方法是遵循'静态类'的模式 - 对于没有静态数据的实例,通常静态数据属于'manager'类。然后在显式的“初始化”调用中处理静态数据初始化,在管理器类的显式“关闭”调用中处理销毁,该类只有静态数据和静态成员函数。

你可能不得不使用一个新的或删除并明确你正在做什么 - 在这个意义上你否定了自动机制为你工作的优势,但作为交换,你得到可靠和易于调试的初始化和关闭例程

这种方法基本上创建了一个单例,因此没有管理器类的实例 - 基本上是静态数据的加载和一些带有类语法的C函数提供了封装的好处(例如私有成员不能在类外访问)

在许多情况下,这对编译器也很友好,因为它知道你的所有数据在哪里以及如何处理它

答案 2 :(得分:0)

如果需要静态对象使用的对象,请在 构造函数或析构函数,通常最好使用 单身模式的变化。这解决了顺序 初始化问题,如果你做得对,那么对象就会 永远不会被破坏,所以不应该有破坏的顺序 问题。

因为你的应用程序显然是多线程的(因为你有 一个互斥体),你应该采取通常的预防措施来制作 对象线程安全,通过在输入之前确保初始化 主要。基本想法是这样的:

template <typename T, char const* id>
class StaticInstanceWrapper
{
    static T* myObject;
public:
    static T& instance();
};

template <typename T, char const* id>
T* StaticInstanceWrapper<T, char const* id>::myObject =
        &StaticInstanceWrapper<T>::instance();

template <typename T, char const* id>
T& StaticInstanceWrapper<T>::instance()
{
    if ( myObject == NULL ) {
        myObject = new T;
    }
    return *myObject;
}

然后,您将静态对象定义为static StaticInstanceWrapper<Whatever> obj;,并将其作为 obj.instance().someFunction(),而不仅仅是 obj.someFunction()(不会编译,因为obj没有 有一个someFunction()成员。

请注意,StaticInstanceWrapper的每个实例都有一个 不同的类型,所以有独特的静态成员,你必须 强制单独实例化模板。这就是我们的原因 有id模板参数;这个论点的类型可以 实际上是任何东西,只要每个实例都有一个 唯一标识符。在实践中,我可能会使用宏 定义,类似于:

#define DEFINE_STATIC_INSTANCE_WRAPPER(type, name) \
char const PASTE(name, _Identifier)[] = STRINGIZE(name); \
StaticInstanceWrapper<type, PASTE(name, _Identifier)> name

这可以确保每个实例都具有唯一的ID。 (如果你想 为了获得更好的体验,你也可以在__LINENO__中进行训练,但是 既然这个名字在范围上必须是独一无二的,我对此表示怀疑 这是必要的。)