谁负责销毁块作用域的静态 Singleton 实例?

Who is responsible for destructing the block scoped static Singleton instance?

我无法理解下面的程序是如何编译成功的。

class SomeClass {
public: /** Singleton **/
    static SomeClass &instance() {
        static SomeClass singleInstance;

        return singleInstance;
    };

private: 
    SomeClass() = default;
    SomeClass(const SomeClass&) = delete;
    SomeClass &operator=(const SomeClass&) = delete;

    ~SomeClass() {}
};

int main() 
{
    SomeClass::instance();

    // SomeClass::instance().~SomeClass(); // Compiles if destructor was public

    return 0;
}

很快,在构造过程中,编译器将析构函数保存到将在程序最后调用的函数列表中。最后,函数列表,包括析构函数,一个一个被调用,安全销毁。


底层机制

该机制的核心是C标准库提供的exit()atexit(..)函数。在程序编译期间,编译器会在您的 block-scoped 静态变量周围注入一些其他代码。伪表示如下。

static SomeClass& instance() {
    static SomeClass singleInstance;

    /*** COMPILER GENERATED ***/
    // Guard variable generated by the compiler
    static bool b_isConstructed = false;

    if(!b_isConstructed)
        ConstructInstance();    // Constructs the Singleton instance
    
        b_isConstructed = true;

        // Push destructor to the list of exit functions
        atexit(~SomeClass());
    }
    /*** COMPILER GENERATED ***/

    return singleInstance;
};

这里的重点是调用 atexit(~SomeClass()) 并将析构函数注册到 exit() 函数的自动调用列表中,当您从 [=15] return 时隐式调用该函数=].由于使用函数指针而不是直接引用私有析构函数方法,因此跳过了访问说明符保护机制。