これを行うことは非常に悪い考えであることが判明しました。起こっている奇妙なことの量は途方もないです。
何が起こっていた
shared_ptr には、ハンドラーに入る 2 の use_count がありました。1 つの参照は PidManager 自体にあり、もう 1 つは PidManager のクライアントにありました。shared_ptr (~PidManager() ) のデストラクタを呼び出すと、use_count が 1 減ります。次に、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 が一貫性のない状態にあるときにハンドラーが呼び出されるという問題が適切に回避されます。