c++设计模式:单件模式(Singleton Pattern)

news/2024/7/3 13:21:46 标签: 设计模式, c++, destructor, constructor, delete, 多线程

定义:单件模式确保一个类只有一个实例,并提供一个全局访问点

实现一:

复制代码
#include <iostream>
using namespace std;

class CSingleton
{
public:
    static CSingleton* getInstance();
    static void cleanInstance();
    int getValue();
    void setValue(int iValue);
private:
    int m_iValue;
    static CSingleton* m_pSingleton;
    CSingleton();
    ~CSingleton();
};

CSingleton* CSingleton::m_pSingleton = NULL;

CSingleton::CSingleton()
{
    cout << "Constructor" << endl;
}

CSingleton::~CSingleton()
{
    cout << "Destructor" << endl;
}

CSingleton* CSingleton::getInstance()
{
    if (NULL == m_pSingleton)
    {
        m_pSingleton = new CSingleton();
    }
    return m_pSingleton;
}

void CSingleton::cleanInstance()
{
    delete m_pSingleton;
}

int CSingleton::getValue()
{
    return m_iValue;
}

void CSingleton::setValue(int iValue)
{
    m_iValue = iValue;
}

int main()
{
    CSingleton* pSingleton1 = CSingleton::getInstance();
    CSingleton* pSingleton2 = CSingleton::getInstance();
    pSingleton1->setValue(123);
    if (pSingleton1->getValue() == pSingleton2->getValue())
    {
        cout << "Two objects is the same instance" << endl;
    }
    else
    {
        cout << "Two objects isn't the same instance" << endl;
    }

    CSingleton::cleanInstance();
    return 0;
}
复制代码

相信大多数的同仁都喜欢使用上边这种单件模式的实现方法,如果在单线程的情况下,是没有问题的,但如果是多线程,那么就极有可能会返回两个不同的对象,在调用

CSingleton::getInstance的时候,两个线程如果都同时运行完if判断,而又还没有调用到构造函数的话,想象下后果吧。那该怎么办呢?看下边这个实现吧。
实现二:
复制代码
#include <iostream>
using namespace std;

class CSingleton
{
public:
    static CSingleton* getInstance();
    static void cleanInstance();
    int getValue();
    void setValue(int iValue);
private:
    int m_iValue;
    static CSingleton* m_pSingleton;
    CSingleton();
    ~CSingleton();
};

// 在进程运行开始就实例化该单件,又称“急切”创建实例
CSingleton* CSingleton::m_pSingleton = new CSingleton();

CSingleton::CSingleton()
{
    cout << "Constructor" << endl;
}

CSingleton::~CSingleton()
{
    cout << "Destructor" << endl;
}

CSingleton* CSingleton::getInstance()
{
    return m_pSingleton;
}

void CSingleton::cleanInstance()
{
    delete m_pSingleton;
}

int CSingleton::getValue()
{
    return m_iValue;
}

void CSingleton::setValue(int iValue)
{
    m_iValue = iValue;
}

int main()
{
    CSingleton* pSingleton1 = CSingleton::getInstance();
    CSingleton* pSingleton2 = CSingleton::getInstance();
    pSingleton1->setValue(123);
    if (pSingleton1->getValue() == pSingleton2->getValue())
    {
        cout << "Two objects is the same instance" << endl;
    }
    else
    {
        cout << "Two objects isn't the same instance" << endl;
    }

    CSingleton::cleanInstance();
    return 0;
}
复制代码
哈哈,看清楚了吗?就是在进程运行的时候就对这个单件进行实例化,可是这样似乎又不能达到延迟实例化的目的啦。如果我们的对象对资源占用非常大,而我们的进行在整个过程中其实并没有用到这个单件,那岂不是白白浪费资源了嘛。还有更好的办法。
实现三:
复制代码
#include <iostream>
using namespace std;

class CSingleton
{
public:
    static CSingleton* getInstance();
    int getValue();
    void setValue(int iValue);
private:
    int m_iValue;
    CSingleton();
    ~CSingleton();
};

CSingleton::CSingleton()
{
    cout << "Constructor" << endl;
}

CSingleton::~CSingleton()
{
    cout << "Destructor" << endl;
}

CSingleton* CSingleton::getInstance()
{
    static CSingleton single;
    return &single;
}

int CSingleton::getValue()
{
    return m_iValue;
}

void CSingleton::setValue(int iValue)
{
    m_iValue = iValue;
}

int main()
{
    cout << "Process begin" << endl;
    CSingleton* pSingleton1 = CSingleton::getInstance();
    CSingleton* pSingleton2 = CSingleton::getInstance();
    pSingleton1->setValue(123);
    if (pSingleton1->getValue() == pSingleton2->getValue())
    {
        cout << "Two objects is the same instance" << endl;
    }
    else
    {
        cout << "Two objects isn't the same instance" << endl;
    }
    return 0;
}
复制代码
看下运行结果吧:

Process begin
Constructor
Two objects is the same instance
Destructor

是不是跟预想的一样呢?把单件声明为成员函数中的静态成员,这样既可以达到延迟实例化的目的,又能达到线程安全的目的,而且看结果的最后,是不是在程序退出的时候,还自动的调用了析构函数呢?这样我们就可以把资源的释放放到析构函数里边,等到程序退出的时候,进程会自动释放这些静态成员的。


http://www.niftyadmin.cn/n/1208954.html

相关文章

HTTP大文件(百M以上)的上传下载实现技术

需求&#xff1a; 项目要支持大文件上传功能&#xff0c;经过讨论&#xff0c;初步将文件上传大小控制在20G内&#xff0c;因此自己需要在项目中进行文件上传部分的调整和配置&#xff0c;自己将大小都以20G来进行限制。 PC端全平台支持&#xff0c;要求支持Windows,Mac,Linu…

C++时间戳转化(涉及GMT CST时区转化)

问题由来 时间戳转换&#xff08;时间戳&#xff1a;自 1970 年1月1日&#xff08;00:00:00 &#xff09;至当前时间的总秒数。&#xff09; #include <stdio.h> #include <time.h>int main(int argc, const char * argv[]) { time_t t;struct tm *p;t140841345…

VS2010下安装boost库

1.去www.boost.org下载最新的boost&#xff0c;我下载了boost_1_46_1.7z 2.&#xff08;我放在D:/cpp目录下&#xff09;解压到当前文件夹 3.打开VS2010->VS TOOLS->VS命令提示 4.CD D:/cpp/boost_1_46_1 5.输入bootstrap&#xff0c;便生成bjam.exe文件 6.输入bjam too…

Web大文件(百M以上)的上传下载实现技术

最近遇见一个需要上传超大大文件的需求&#xff0c;调研了七牛和腾讯云的切片分段上传功能&#xff0c;因此在此整理前端大文件上传相关功能的实现。 在某些业务中&#xff0c;大文件上传是一个比较重要的交互场景&#xff0c;如上传入库比较大的Excel表格数据、上传影音文件等…

jpg,pdf文件变大技巧

日常工作中&#xff0c;我们经常发现某些jpg&#xff0c;pdf要上传到网站时提示文件过大&#xff0c;此时我们都可以通过下载jpg压缩工具把文件变小&#xff0c;但有时&#xff0c;我们需要对某些jpg&#xff0c;pdf文件变大&#xff0c;怎么办呢&#xff0c;我就碰到一个朋友突…

sleep函数简介

在VC中使用带上头文件#include <windows.h>注意:在VC中Sleep中的第一个英文字符为大写的"S"在标准C中是sleep, 不要大写.. 下面使用大写的来说明,, 具体用什么看你用什么编译器. 简单的说VC用Sleep, 别的一律使用sleep.Sleep函数的一般形式:Sleep(unisgned lon…

FCKEditor富文本实现导入word功能

这种方法是servlet&#xff0c;编写好在web.xml里配置servlet-class和servlet-mapping即可使用 后台&#xff08;服务端&#xff09;java服务代码&#xff1a;&#xff08;上传至ROOT/lqxcPics文件夹下&#xff09; <% page language"java" import"java.ut…

nginx平滑升级、在线添加模块(tengine 动态加载模块)

http://www.orzace.com/how-to-upgrade-nginx/下面是nginx替换成tengine再加上lua 模块&#xff0c;&#xff08;tengine-2.0.1版本暂时无法动态加载lua模块&#xff0c;只能编译加载&#xff09;安装系统所需web软件1.下载luajit,官网 http://luajit.org/ wget http://lua…