我们如何将 Phoenix Singleton 放在同一个地址? C++
How we place Phoenix Singleton on same address? C++
下面的代码说明了 Phoenix Singleton described in Andrey Alexandrescu's 现代 C++ 设计书。
Singleton& Instance()
{
if (!pInstance_)
{
// Check for dead reference
if (destroyed_)
{
OnDeadReference();
}
else
{
// First call—initialize
Create();
}
}
return pInstance_;
}
void Singleton::OnDeadReference()
{
// Obtain the shell of the destroyed singleton
Create();
// Now pInstance_ points to the "ashes" of the singleton
// - the raw memory that the singleton was seated in.
// Create a new singleton at that address
new(pInstance_) Singleton;
// Queue this new object's destruction
atexit(KillPhoenixSingleton);
// Reset destroyed_ because we're back in business
destroyed_ = false;
}
static void Create();
{
// Task: initialize pInstance_
static Singleton theInstance;
pInstance_ = &theInstance;
}
void Singleton::KillPhoenixSingleton()
{
// Make all ashes again
// - call the destructor by hand.
// It will set pInstance_ to zero and destroyed_ to true
pInstance_->~Singleton();
}
virtual ~Singleton()
{
pInstance_ = 0;
destroyed_ = true;
}
Singleton* Singleton::pInstance_ = 0;
bool Singleton::destroyed_ = false;
书中引述:
Let's analyze the flow of events. During the application exit sequence, Singleton's destructor is called.
The destructor resets the pointer to zero and sets destroyed_ to true. Now assume some global object
tries to access Singleton again. Instance calls OnDeadReference. OnDeadReference
reanimates Singleton and queues a call to KillPhoenixSingleton, and Instance successfully
returns a reference to a valid Singleton object. From now on, the cycle may repeat.
我的问题是 - 如果我们在析构函数中分配给指针 pInstance_ = 0
,而不是它分配给一个本地静态引用,该引用应该在该点被删除,我们如何在 0 地址放置一个新对象?请告诉我我遗漏了什么。如果有人能向我解释流程,我将不胜感激。谢谢
"Phoenix" 这个名字来自传说中的鸟,它死去、着火并从灰烬中重生。
在这种情况下,是的,Singleton 可以死掉,析构函数运行,pInstance
变成 nullptr
,然后它就消失了 - 直到它需要复活。发生这种情况时,Create
在 new (pInstance) Singeton
重新创建对象之前使 pInstance
非空。
[编辑]
您需要了解对象生命周期和存储持续时间的规则。显然,对象的存储必须在创建对象之前分配,并且在对象被销毁之前不能释放存储。两者之间的间隔称为 存储持续时间 。现在,有static storage duration这样的东西。在程序退出之前不会回收此类存储,即使该存储中的对象已被销毁。在命名空间范围内定义的变量 ("globals") 和 static
变量具有此静态存储持续时间。
因此,theSingleton
的存储具有静态存储持续时间,即使存在 destroyed
的对象,pInstance
也可以指向此存储。请注意,destroyed
和 pInstance
变量本身也具有静态存储持续时间,因为它们是全局变量。
下面的代码说明了 Phoenix Singleton described in Andrey Alexandrescu's 现代 C++ 设计书。
Singleton& Instance()
{
if (!pInstance_)
{
// Check for dead reference
if (destroyed_)
{
OnDeadReference();
}
else
{
// First call—initialize
Create();
}
}
return pInstance_;
}
void Singleton::OnDeadReference()
{
// Obtain the shell of the destroyed singleton
Create();
// Now pInstance_ points to the "ashes" of the singleton
// - the raw memory that the singleton was seated in.
// Create a new singleton at that address
new(pInstance_) Singleton;
// Queue this new object's destruction
atexit(KillPhoenixSingleton);
// Reset destroyed_ because we're back in business
destroyed_ = false;
}
static void Create();
{
// Task: initialize pInstance_
static Singleton theInstance;
pInstance_ = &theInstance;
}
void Singleton::KillPhoenixSingleton()
{
// Make all ashes again
// - call the destructor by hand.
// It will set pInstance_ to zero and destroyed_ to true
pInstance_->~Singleton();
}
virtual ~Singleton()
{
pInstance_ = 0;
destroyed_ = true;
}
Singleton* Singleton::pInstance_ = 0;
bool Singleton::destroyed_ = false;
书中引述:
Let's analyze the flow of events. During the application exit sequence, Singleton's destructor is called. The destructor resets the pointer to zero and sets destroyed_ to true. Now assume some global object tries to access Singleton again. Instance calls OnDeadReference. OnDeadReference reanimates Singleton and queues a call to KillPhoenixSingleton, and Instance successfully returns a reference to a valid Singleton object. From now on, the cycle may repeat.
我的问题是 - 如果我们在析构函数中分配给指针 pInstance_ = 0
,而不是它分配给一个本地静态引用,该引用应该在该点被删除,我们如何在 0 地址放置一个新对象?请告诉我我遗漏了什么。如果有人能向我解释流程,我将不胜感激。谢谢
"Phoenix" 这个名字来自传说中的鸟,它死去、着火并从灰烬中重生。
在这种情况下,是的,Singleton 可以死掉,析构函数运行,pInstance
变成 nullptr
,然后它就消失了 - 直到它需要复活。发生这种情况时,Create
在 new (pInstance) Singeton
重新创建对象之前使 pInstance
非空。
[编辑]
您需要了解对象生命周期和存储持续时间的规则。显然,对象的存储必须在创建对象之前分配,并且在对象被销毁之前不能释放存储。两者之间的间隔称为 存储持续时间 。现在,有static storage duration这样的东西。在程序退出之前不会回收此类存储,即使该存储中的对象已被销毁。在命名空间范围内定义的变量 ("globals") 和 static
变量具有此静态存储持续时间。
因此,theSingleton
的存储具有静态存储持续时间,即使存在 destroyed
的对象,pInstance
也可以指向此存储。请注意,destroyed
和 pInstance
变量本身也具有静态存储持续时间,因为它们是全局变量。