2012-05-19 38 views
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智能指针很容易。但是,如果可能的话,我想避免使用额外的库来保持尽可能低的依赖性。

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

+0

请修复您的缩进和范围界定。 –

+0

另外,请考虑创建一个简短的连贯测试用例来说明您的'A'实例是否与其他一切相关。目前有点令人困惑。 –

+0

请注意,'register'是C++和C中的关键字,因此您的代码无法编译。 –

回答

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对象的析构函数在之后的之后的所有A -destructors被排序。

+0

引用的语句是不是指两个对象都是静态存储持续时间的情况?在我的情况下,只有一个是“静态”。 – ritter

+0

我不明白:“静态A型的第一个构造函数”。 'A'不是静态的。 – ritter

+0

@Frank:“静态”并不意味着你的想法。示例中的所有内容都有静态存储时间。关键字'static'只是用静态存储持续时间来创建对象的许多方法之一。 –

2

B实例是静态的,因此在创建B单例之后,它将超过创建的任何A实例。

+0

如果所有对象都在同一个编译单元中,这当然是正确的。这里不是这种情况。我不确定是否在编译单元中也会延迟静态对象销毁 – ritter

+0

@Frank我无法看到它如何不适用于各个编译单元。 – juanchopanza

+0

是的,设置没问题。但是原因在于调用构造函数的顺序以及静态的事实。如果你同时指的是两种情况,你说得对 – ritter