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

发布于 2025-01-15 14:45:46 字数 590 浏览 2 评论 0原文

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

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;
}
  • 谁负责调用 Singleton 的析构函数 实例?
  • 底层机制如何访问私有方法?

I couldn't understand how the program below compiles successfully.

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;
}
  • Who is responsible for calling the destructor of the Singleton
    instance?
  • How does the underlying mechanism access a private method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一抹淡然 2025-01-22 14:45:46

不久,在构造过程中,编译器将析构函数保存到将在程序最后调用的函数列表中。最后,包括析构函数在内的函数列表被一一调用,并发生安全销毁。


底层机制

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

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() 函数的自动调用列表中,该函数在返回时隐式调用来自main(..)。由于使用函数指针而不是直接引用私有析构函数方法,因此跳过了访问说明符保护机制。

Shortly, during the construction, the compiler saves the destructor to a list of functions that will be called at the very end of the program. In the end, the list of functions, including the destructors, are called one by one and the safe destruction occurs.


Underlying Mechanism

The core of the mechanism is the exit() and atexit(..) functions provided by the C standard library. During the compilation of the program, the compiler injects some other codes around your block-scoped static variable. A pseudo representation is as below.

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;
};

The point here is to call the atexit(~SomeClass()) and register the destructor to the automatic call list of the exit() function which is implicitly called when you return from the main(..). As the function pointers are used instead of directly referring to the private destructor method, the access specifier protection mechanism is skipped.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文