有“套路”的C++单例模式源码解析:让你的程序更优雅

552 阅读3分钟

诉求:希望我们的 class 只有一个对象

源码解析

class CLbTransfLog
{
public:
    ~CLbTransfLog(void)
    {
    }

    static CLbTransfLog* GetInstancePtr(void)
    {
            static CLbTransfLog m_sLBIMLog;

            return &m_sLBIMLog;
    }
private:
    CLbTransfLog(void)
            : m_strLogFileName(_T(""))
            , m_strDBLogFileName(_T(""))
    {
    }
    CLbTransfLog(const CLbTransfLog& other);
}

这是一个单例模式的实现。单例模式是一种创建型设计模式,用于确保一个类只有一个实例,并提供一个访问该实例的全局访问点

单例模式的一般特点

这段代码也可以反映单例模式的一般特点

  • 类的构造函数是私有的

    CLbTransfLog 类的构造函数是私有的,因此外部无法直接创建该类的对象。

  • 提供一个访问类实例的全局访问点

    这里提供了一个静态的 GetInstancePtr() 方法,用于获取 CLbTransfLog 类的唯一实例。

  • 使用 static 创建静态局部变量

    GetInstancePtr() 方法内部使用静态局部变量实现了惰性初始化,确保仅在首次调用该方法时才会创建实例。

    并且这个对象 static CLbTransfLog m_sLBIMLog;它不属于任何一个类的对象,从创建的一刻,就在内存中某一个区域就存在了,并且只有一份。因此,无论多少次调用 GetInstancePtr() 方法,它都返回同一个实例的指针。

这种实现方式的好处在于,它可以确保系统中只有一个 CLbTransfLog 类的实例,从而避免了实例的重复创建和资源浪费。此外,它还提供了一个全局访问点,使得任何地方都可以访问到该实例,方便了程序的编写和管理。

我们还看见过下面的写法

class CLbTransfLog
{
public:
    ~CLbTransfLog(void)
    {
    }

    static CLbTransfLog& GetInstancePtr
    {
            return m_sLBIMLog;
    }
    void setup(){...};
private:
    CLbTransfLog(void)
            : m_strLogFileName(_T(""))
            , m_strDBLogFileName(_T(""))
    {
    }
    CLbTransfLog(const CLbTransfLog& other);
    static CLbTransfLog& m_sLBIMLog;
}

这种写法是在没有人创建 CLbTransfLog 对象的时候,CLbTransfLog 就有一个变量了,占有一个空间了。

不想让外界创建 CLbTransfLog ,就把他的构造函数放在 private 中。

外界只能通过静态函数 GetInstancePtr 函数,获取到唯一的 m_sLBIMLog,接下来就可以通过唯一的 m_sLBIMLog,获取类中的各种函数了,比如,m_sLBIMLog.setup()。

可以看出来这种写法有一个缺点,如果外界没有用到这个类,这个类的静态变量仍然存在,这就有一点浪费,所以更好的写法还是第一种。

两种写法的区别

这两种写法的区别在于,第二种写法将 m_sLBIMLog 定义为静态局部变量,外界没有使用这个类的时候,这个类的静态变量仍然存在。而第一种写法将 m_sLBIMLog 定义为静态成员变量,并通过类外部的创建来初始化它,如果外界没有人使用这个类,将不会创建这个单例。

单例模式模板总结

第一种(更好,自己编码使用)

class A
{
public:
    static A& getInstance();
    setup(){...}
    ...
private:
    A(); // 类私有构造函数
    A(const A& rhs);
    ...
}

A& A::getInstance()
{
    static A a; // 期望只有一份的类实例
    return a;
}

指针形式

class A
{
public:
    static A* getInstance();
    setup(){...}
    ...
private:
    A(); // 类私有构造函数
    A(const A& rhs);
    ...
}

A* A::getInstance()
{
    static A a; // 期望只有一份的类实例
    return &a;
}

第二种(会识别)

class A
{
public:
    static A& getInstance() {return a;};
    setup(){...};
    ...
private:
    A(); // 类私有构造函数
    A(const A& rhs);
    static A a; // 期望只有一份的类实例
    ...
}

指针的形式

class A
{
public:
    static A* getInstance();
    static void releaseInstance();
private:
    A();
    ~A();
private:
    static A* m_pInstance;
}

A* A::m_pInstance = nullptr;//定义,赋初值

A* A::getInstance()
{
    if (nullptr == m_pInstance)
    {
        m_pInstance = new A();
    }
    return m_pInstance;
}

void A::ReleaseInstance()
{
    if (nullptr != m_pInstance)
    {
        delete m_pInstance;
        m_pInstance = nullptr;
    }
}