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,它警告第二种方式:
[Potential Pitfall]: This form of the singleton can present a problem
because of the life expectancy of the object. If one singleton is
instantiated within another,one must be keenly aware of the
destructor call sequence.
解决方法
典型的单身人士
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从它的灰烬中回来,如果它在它死后需要它;但是,在破坏期间获得线程安全性和安全性很难实现.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。