5

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

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 智能指针可以轻松完成这样的事情。但是,如果可能的话,我想避免使用额外的库来保持尽可能低的依赖。

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

4

2 回答 2

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。通过上述子句,这保证了B impl-object的析构函数在所有-destructor之后A排序。

于 2012-05-19T18:11:23.567 回答
2

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

于 2012-05-19T17:54:07.887 回答