c – 陷阱:静态堆栈变量Singleton类
我已经有一些使用指针的单例类:
class Logger { public: static Logger* Instance() { if (!m_pInstance) m_pInstance = new Logger; return m_pInstance; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); static Logger* m_pInstance; }; 但是,有一种更简单的方法,使用引用: class Logger { public: static Logger& Instance() { static Logger theLogger; return theLogger; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); ~Logger(); }; 阅读文章C++ Singleton design pattern,它警告第二种方式:
但我无法理解,有人能告诉我一个不好的用法,我应该避免它吗? 解决方法
两种选择确实存在问题.
典型的单身人士 class Logger { public: static Logger* Instance() { if (!m_pInstance) m_pInstance = new Logger; return m_pInstance; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); static Logger* m_pInstance; }; 此代码不是线程安全的,因此对新Logger的调用可能会多次发生(在不同的线程中).它还会泄漏Logger实例(因为它永远不会被删除),如果应该执行析构函数,这可能是一个问题. 梅耶的辛格尔顿 class Logger { public: static Logger& Instance() { static Logger theLogger; return theLogger; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); ~Logger(); }; Meyer’s Singleton的问题确实是由于对象的破坏.从main返回后,所有全局变量的析构函数将按照构造这些全局变量的相反顺序运行1.这就好像这些全局变量是在堆栈上构造的. 如果在Logger之前构造了一个对象,并试图在它自己的析构函数中使用它;然后它将使用已经被破坏的对象,导致未定义的行为. 1更准确地说,它们的构造函数以相反的顺序完成. 最简单的选择是重新审视典型单身人士: class Logger { public: static Logger& Instance() { static Logger* L = new Logger; return *L; } private: ... }; 这现在是线程安全的,但仍然泄漏.但实际上这里需要泄漏,因为它可以保证这个对象比任何其他析构函数都被调用的时间更长.警告:如果你曾经在析构函数中做过一些事情,它将永远不会运行. 还有其他的变化,例如Alexandrescu的凤凰Singleton从它的灰烬中回来,如果它在它死后需要它;但是,在破坏期间获得线程安全性和安全性很难实现. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |