如何强制析构函数的调用顺序

时间:2012-05-19 17:51:13

标签: c++ constructor destructor

我正在尝试正确设置以下设置:

给定的应用程序(具有多个源文件,编译单元)具有在许多编译单元中定义的类型class A的全局变量。 这些应该由一个新的“管理”来引入class B(其中只有一个实例应该存在),因为在创建时它们会在B类实例中“注册”它们并在销毁时“注销”。

为构造函数设置工作非常简单。可以使用:

types.h

class B {
  static B& Instance() {
    static B singleton;
    return singleton;
  }
  void registerA( const A& a ) { 
  // whatever
  }
};


class A {
  A() { B::Instance().registerA( this ); }
};

如何让析构函数正确?如果使用:

class A {
  A() { B::Instance().registerA( this ); }
  ~A() { B::Instance().signoffA( this ); }
};

然后可以在B的析构函数之前调用A的析构函数。 然后,类A的实例在刚刚创建的B实例中注销。

测试用例是一个多源文件设置,在命名空间中定义了class A的实例:

file1.cc

#include "types.h"
namespace C {
   A a;
}

file2.cc

#include "types.h"
namespace C {
   A b;
}

我想可以使用Boost智能指针轻松做到这一点。但是,如果可能的话,我希望避免使用额外的库来尽可能降低依赖性。

可能有所帮助:所有全局变量都在命名空间中。

2 个答案:

答案 0 :(得分:4)

我觉得你很好。这是关于“终止”的3.6.3:

  

如果具有静态存储持续时间的对象的构造函数或动态初始化的完成先于另一个对象的顺序排序,则在第一个析构函数的启动之前对第二个析构函数的析构函数的完成进行排序。

假设您有以下设置:

struct A;

struct B
{
    static B & get() { static B impl; return impl; }
    void registrate(A *);

private:
    B() { /* complex stuff */ }
    // ...
};

struct A { A() { B::get().registrate(this); } };

A a1;

现在无论发生什么,静态A - 类型对象的第一个构造函数都会调用B::get(),它会在第一个impl完成之前对静态A对象的构造进行排序。 1}} - 构造。通过上面的子句,这可以保证B impl - 对象的析构函数在所有A - 析构函数之后排序。

答案 1 :(得分:2)

B实例是静态的,因此它将比创建A单例后创建的任何B实例更长。