C++单例模式

C++ singleton pattern

本文关键字:单例模式 C++      更新时间:2023-10-16

考虑以下来自yolinux的singleton模式的设计(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&){};
提前谢谢。

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

这将导致链接器错误,该错误不是显式消息。这些方法是默认生成的,所以你必须强制它们是私有

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

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

删除不是强制性的,单例在没有这个功能的情况下也能很好地工作,所以如果你的编译器不支持这个功能,你可以把它设为私有的,它也能工作。此功能提供明确的错误消息,但不会影响单例本身的行为。

有关删除功能的更多信息,您可以在这里查看:

=函数声明后删除的含义

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

将析构函数设为私有函数有什么用?

从您的链接:

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

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

注释很好地解释了这一点。

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

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

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

T& instance()
{
    static T _instance;
    return _instance;
}

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

由于C++11标准,您也可以使用:

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

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

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

•因为它们是私有的,这将导致任何试图使用它们但无法访问类的私有部分的人在编译时出错。

•这会让朋友(和类本身)在链接时(如果你在那里检查了这些)或很可能在运行时(试图加载库时)以未定义符号的形式出现错误。