设计模式之——单例

设计模式之——单例

单例是在程序设计中用得比较多的一种,其应用场景如下:

  1. 日志类。日志类往往对应实际的日志文件或者数据库,这种文件或数据库只存在一份,因此我们实例化的时候只需要实例化一次就够了,也就是说对于日志类,其实例化的对象在程序中有且只有一个。
  2. IO操作类,比如串口,SPI等设备。像这些外接设备在现实中也是只有一个,因此我们实例化也只需要实例化一次就够了。

单例的实现方式

饿汉式

对象在程序执行的时候就会被创建,在程序结束时自动释放。下面我们写一段比较简单的程序来说明这个问题。

#ifndef CSINGLETONEH_H
#define CSINGLETONEH_H

#include <iostream>
using namespace std;
/*
 * C++单例的饿汉实现方式
 *
 */

class CSingletonEH
{
public:
    static CSingletonEH *getInstance();

private:
    CSingletonEH(int arg);
    ~CSingletonEH();

private:
    static CSingletonEH m_instance;

};

#endif // CSINGLETONEH_H
#include "CSingletonEH.h"

//定义静态的单例对象,程序执行时实例化,程序结束时释放(析构)
CSingletonEH CSingletonEH::m_instance(1);

CSingletonEH *CSingletonEH::getInstance()
{
    return &m_instance;
}

CSingletonEH::CSingletonEH(int arg)
{
    cout << "CSingletonEH object create!" << endl;
    cout << "create arg:" << arg << endl;
}

CSingletonEH::~CSingletonEH()
{
    cout << "CSingletonEH object destroy!" << endl;
}

上述程序中m_instance在类内声明为static的对象,在类外定义这个对象。毫无疑问,这个对象的生存周期和程序的生存周期一样,并且在程序执行时就被创建了。这里我们分析一下其优缺点。
优点:

  1. 对象的生命周期和程序一样,不用担心其内存释放和泄露问题。
  2. 线程安全(仅限于对象的创建,后续补充说明)
    缺点:
  3. 内存浪费,因为对象在程序执行时就会被创建,不管有没有用到该类
  4. 对象的创建不灵活,因为对象在定义时就被创建了,不能根据实际传入构造参数。

懒汉式

在第一次调用时创建对象,后续调用时直接返回已经创建的对象。

静态局部变量实现方式

这种实现方式是利用局部静态 只会被初始化一次。

#ifndef CSINGLETONLH_H
#define CSINGLETONLH_H

#include <pthread.h>
#include <iostream>

using namespace std;

/*
 * C++单例的懒汉方式
 * 对象在栈空间
*/

class CSingletonLH
{
public:
    static CSingletonLH *getInstance(int val = 0);

private:
    CSingletonLH(int val);
    ~CSingletonLH();

private:


};

#endif // CSINGLETONLH_H

#include "CSingletonLH.h"

//初始化静态锁
static pthread_mutex_t instanceMutex = PTHREAD_MUTEX_INITIALIZER;

CSingletonLH *CSingletonLH::getInstance(int val)
{
    //防止产生多个对象,解决线程安全问题
    pthread_mutex_lock(&instanceMutex);
    static CSingletonLH singleton(val);
    pthread_mutex_unlock(&instanceMutex);

    return &singleton;
}

CSingletonLH::CSingletonLH(int val)
{
    (void)val;//do something..
    cout << "CSingletonLH Object Create!" << endl;
}

CSingletonLH::~CSingletonLH()
{
    cout << "CSingletonLH Object Destroy!" << endl;
}

静态指针成员变量实现方式

需要在类内专门定义一个静态对象用于释放内存

#ifndef CSINGLETONLH_HEAP_H
#define CSINGLETONLH_HEAP_H

#include <pthread.h>
#include <iostream>

using namespace std;

/*
 * C++单例的懒汉方式
 * 对象存放在堆空间,并在类内声明一个static的对象用于释放内存
*/
class CSingletonLH_Heap
{
public:
    static CSingletonLH_Heap *getInstance();

private:
    CSingletonLH_Heap();
    ~CSingletonLH_Heap();

private:
    static CSingletonLH_Heap *m_instance;

private:
    class GarbageCollector {
     public:
         ~GarbageCollector() {
             if ( m_instance != NULL ) {
                 delete m_instance;
             }
         }
     };

    static GarbageCollector gc;
};

#endif // CSINGLETONLH_HEAP_H
#include "CSingletonLH_Heap.h"

CSingletonLH_Heap *CSingletonLH_Heap::m_instance = NULL;
//初始化静态锁
static pthread_mutex_t instanceMutex = PTHREAD_MUTEX_INITIALIZER;
//定义一个static GarbageCollector对象,在GarbageCollector的析构函数中释放内存
CSingletonLH_Heap::GarbageCollector CSingletonLH_Heap::gc;

CSingletonLH_Heap *CSingletonLH_Heap::getInstance()
{
    pthread_mutex_lock(&instanceMutex);
    if ( NULL == m_instance )
    {
        m_instance = new CSingletonLH_Heap();
    }
    pthread_mutex_unlock(&instanceMutex);

    return m_instance;
}

CSingletonLH_Heap::CSingletonLH_Heap()
{
    cout << "CSingletonLH_Heap Object Create!" << endl;
}

CSingletonLH_Heap::~CSingletonLH_Heap()
{
    cout << "CSingletonLH_Heap Object Destroy!" << endl;
}

静态智能指针成员变量实现方式

通过智能指针自动释放内存

#ifndef CSINGLETONLH_HEAPSHAREPTR_H
#define CSINGLETONLH_HEAPSHAREPTR_H

#include <pthread.h>
#include <iostream>
#include <memory>

using namespace std;

class CSingletonLH_HeapSharePtr
{
public:
    static shared_ptr<CSingletonLH_HeapSharePtr> getInstance();
    ~CSingletonLH_HeapSharePtr();

private:
    CSingletonLH_HeapSharePtr();
    CSingletonLH_HeapSharePtr(const CSingletonLH_HeapSharePtr &other);
    CSingletonLH_HeapSharePtr &operator=(const CSingletonLH_HeapSharePtr &other);

private:
    static shared_ptr<CSingletonLH_HeapSharePtr> m_instance;
};

#endif // CSINGLETONLH_HEAPSHAREPTR_H

#include "CSingletonLH_HeapSharePtr.h"

shared_ptr<CSingletonLH_HeapSharePtr> \
CSingletonLH_HeapSharePtr::m_instance(new CSingletonLH_HeapSharePtr());

shared_ptr<CSingletonLH_HeapSharePtr> CSingletonLH_HeapSharePtr::getInstance()
{
    return m_instance;
}

CSingletonLH_HeapSharePtr::CSingletonLH_HeapSharePtr()
{
    cout << "CSingletonLH_HeapSharePtr Object Create!" << endl;
}

CSingletonLH_HeapSharePtr::~CSingletonLH_HeapSharePtr()
{
    cout << "CSingletonLH_HeapSharePtr Object Destroy!" << endl;
}

懒汉三种不同方式的比较

从上面的程序看来,在简单的日常使用中,利用静态局部变量来实现懒汉单例会比较简单,因此个人更偏向于该方式。当然,其他方式也有各自的应用场景,当我们有需要用到单例模式的时候,可以权衡一下实际的应用场景再决定用哪种实现方式。

单例的返回值类型

上述中,单例的返回值类型都是指针。其实我们也可以返回引用。对于两种类型的返回,有以下几点需要注意的。

  1. 当返回指针时,若设计的单例的生命周期跟程序一样,析构函数必须声明为private,防止用户提前释放。
  2. 当返回引用时,只能赋值给引用变量,因为其构造函数,拷贝构造都是private的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值