事实证明,这样做是一个非常糟糕的主意。发生的奇怪事情的数量是巨大的。
发生了什么事
shared_ptr 进入处理程序的 use_count 为 2。一个引用在 PidManager 本身中,另一个在 PidManager 的客户端中。调用 shared_ptr (~PidManager() ) 的析构函数将 use_count 减一。然后,正如 GMan 所暗示的,当调用 exit() 时,静态初始化的 PidManagerPtr instance_ 的析构函数被调用,将 use_count 减少到 0 并导致 PidManager 析构函数被调用。显然,如果 PidManager 有多个客户端,则 use_count 不会下降到 0,这根本不会起作用。
这也提供了一些关于为什么调用 instance_.reset() 不起作用的提示。该调用确实将引用计数减少了 1。但剩余的引用是 PidManager 客户端中的 shared_ptr。shared_ptr 是一个自动变量,因此它的析构函数不会在 exit() 中调用。调用了 instance_ 析构函数,但由于它是 reset(),它不再指向 PidManager 实例。
解决方案
我完全放弃了 shared_ptrs 的使用,并决定改用 Meyers Singleton。现在我的代码如下所示:
void handler(int sig)
{
exit(1);
}
typedef PidManager * PidManagerPtr
PidManagerPtr PidManager::instance()
{
static PidManager instance_;
static bool handler_registered = false;
if(!handler_registered)
{
signal(SIGINT,handler);
handler_registered = true;
}
return &instance_;
}
显式调用 exit 允许静态初始化的 PidManager instance_ 的析构函数运行,因此无需在处理程序中放置其他清理代码。这巧妙地避免了在 PidManager 处于不一致状态时调用处理程序的任何问题。