1

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

现在,当我的程序终止时,它会崩溃。当静态对象“obj”被破坏时,就会发生这种情况。'obj' 的析构函数调用它的静态成员(我自己的互斥锁类型遵循 RAII 惯用语来破坏底层的低级对象)。不幸的是,这个成员碰巧已经被销毁,因为静态对象的初始化顺序(-> 相反的析构函数顺序)是未定义的。

如何干净地生存下来?我很惊讶这种情况并没有更频繁地发生。一般来说,拥有静态的非 POD 成员似乎非常危险。特别是如果您不了解它们的内部结构。

4

3 回答 3

0

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

由于您的应用程序显然是多线程的(因为您有一个互斥锁),您应该采取通常的预防措施来确保对象线程安全,确保在进入 main 之前进行初始化。基本思想是这样的:

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__,但由于无论如何名称必须在范围内是唯一的,我怀疑这是必要的。)

于 2012-11-24T17:39:31.493 回答
0

如果您将它们static放在函数中,那么您将根据谁首先调用该函数来对它们的生命周期进行排序。这就是单例的实现方式。

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

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

不过,你最好避免静态。

于 2012-11-24T16:58:17.577 回答
0

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

我避免这个问题的方法是遵循“静态类”的模式——通常静态数据属于没有静态数据的实例的“管理器”类。然后在显式“初始化”调用中处理静态数据初始化,并在仅具有静态数据和静态成员函数的管理器类上的显式“关闭”调用中处理破坏。

您可能必须使用 new 或 delete 并明确说明您正在做什么 - 从这个意义上说,您否定了自动机制为您工作的优势,但作为交换,您可以获得可靠且易于调试的初始化和关闭例程。

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

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

于 2012-11-24T16:58:27.030 回答