如果驱动器具有副作用,并且从另一个静态对象的破坏者访问对象,该如何进行静态去启动?
-
01-10-2019 - |
题
有一个简单而众所周知的模式可以避免静态初始化惨败, C ++常见问题解答的第10.13节.
在这种标准模式中,有一个权衡取舍,即构造的对象永远不会破坏(如果击曲线没有重要的副作用,这不是问题),或者无法从另一个静态对象的destructor安全地访问静态对象(看 C ++常见问题解答的第10.14节).
因此,我的问题是:如果静态对象的破坏者具有重要的副作用,则如何避免静态去灭绝惨败 和 静态对象必须由另一个静态对象的破坏者访问?
(注意:常见问题解答提到此问题在常见问题解答16.17中回答 C ++常见问题解答:常见问题 M. Cline和G. Lomow。我无法访问这本书,这就是为什么我要问这个问题的原因。)
解决方案
函数静态对象(如全局对象)被保证被破坏(假设它们是创建的)。
破坏的顺序是创造的倒数。
因此,如果一个对象在破坏过程中取决于另一个对象,则必须保证其仍然可用。这是相对简单的,因为您可以通过确保正确完成创建顺序来迫使破坏秩序。
以下链接是关于Singeltons的,但描述了类似的情况及其解决方案:
查找C ++静态初始化顺序问题
如FAQ Lite中所述,推断到懒惰初始化的全球范围的一般情况,我们可以解决这样的问题:
namespace B
{
class B { ... };
B& getInstance_Bglob;
{
static B instance_Bglob;
return instance_Bglob;;
}
B::~B()
{
A::getInstance_abc().doSomthing();
// The object abc is accessed from the destructor.
// Potential problem.
// You must guarantee that abc is destroyed after this object.
// To gurantee this you must make sure it is constructed first.
// To do this just access the object from the constructor.
}
B::B()
{
A::getInstance_abc();
// abc is now fully constructed.
// This means it was constructed before this object.
// This means it will be destroyed after this object.
// This means it is safe to use from the destructor.
}
}
namespace A
{
class A { ... };
A& getInstance_abc()
{
static A instance_abc;
return instance_abc;
}
}
其他提示
只要对另一个对象的静态驱动器首先运行,就可以了。您可以通过在“对象a”之前构造另一个对象来确保这一点。只要两个对象在同一汇编单元中声明,它们就会以它们出现在源中的顺序初始化,并以相反的顺序遭到破坏。
如果您需要跨编译单元发生这种情况,那您就无法运气。更好的是在运行时动态创建它们,并在主的末端销毁它们,而不是使它们静态。
这有点黑客,但我会添加一些静态布尔以跟踪DE初始化的顺序,然后最后一个对象最后进行清理,即使不是所有者。