C ++单例模式

时间:2014-04-21 09:33:05

标签: c++

考虑yolinux(http://www.yolinux.com/TUTORIALS/C++Singleton.html

的单例模式的以下设计
#include <string>

class Logger{
public:
   static Logger* Instance();
   bool openLogFile(std::string logFile);
   void writeToLogFile();
   bool closeLogFile();

private:
   Logger(){};  // Private so that it can  not be called
   Logger(Logger const&){};             // copy constructor is private
   Logger& operator=(Logger const&){};  // assignment operator is private
   static Logger* m_pInstance;
};

有人会解释为什么这里需要Logger(Logger const&){};Logger& operator=(Logger const&){};? 提前谢谢。

6 个答案:

答案 0 :(得分:3)

如果强制复制构造函数和赋值运算符是私有的,那么您将无法编译两个Logger对象的赋值。

这将导致链接器错误,这不是显式消息。 默认情况下会生成这些方法,因此您必须强制它们为私有

在C ++ 11中,他们使用已删除的方法来获得更清晰的消息

   Logger(Logger const&)=delete;             // copy constructor does not exist
   Logger& operator=(Logger const&)=delete;  // assignment operator does not exist

删除不是强制性的,并且单例在没有此功能的情况下运行良好,因此如果您的编译器不支持此功能,您可以将其设置为私有它将起作用。 此功能提供了显式的错误消息,但不会影响单例本身的行为。

有关删除功能的详细信息,请查看此处:

Meaning of = delete after function declaration

您还可以通过将析构函数设为私有来防止对象被破坏。

What is the use of having destructor as private?

答案 1 :(得分:1)

从您的链接:

This design pattern and methodology ensures that only one instance of the C++ class is instantiated.

Logger(Logger const&)是一个允许复制对象的复制构造函数。这是错误的想法。 Logger& operator=(Logger&)也允许复制对象。

答案 2 :(得分:1)

评论很好地解释了这一点。

如果您没有明确定义构造函数和复制构造函数,那么它们将默认创建为public。通过在这里定义它们,您可以确保它们是私有的,因此用户永远不会调用它们。

答案 3 :(得分:1)

将复制构造函数和左值赋值运算符声明为private,以使该类型不可复制。

另一方面,我鼓励你使用Meyers单例而不是基于动态内存:它更容易实现,而不是泄漏(注意严格说你的单例泄漏内存,实例永远不会删除),并且是C ++ 11标准内存模型中定义的线程安全:

T& instance()
{
    static T _instance;

    return _instance;
}

答案 4 :(得分:1)

这些是复制构造函数和复制赋值运算符。如果它们没有被定义为私有,它们将自动生成为公共的,并且实例将是可复制的,这与Singleton模式相矛盾。

自C ++ 11标准以来,您还可以使用:

Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;

这种语法可能更清晰,也可以确保即使是朋友和私人成员也无法复制该对象。

答案 5 :(得分:1)

实现单例行为的传统解决方案是将构造函数声明为private。复制构造函数和赋值运算符(故意没有实现)被声明为私有,以防止出现任何类型的副本

•因为它们是私有的,所以任何试图使用它们而无法访问该类私有部分的人都会导致编译时错误。

•哪些会以未定义符号的形式发生错误的朋友(以及类本身),或者在链接时(如果你在那里检查那些)或者最有可能在运行时(当尝试时)加载库。)