C++中的单例模式

文章介绍了单例模式的基本概念,即确保一个类只有一个实例,并提供全局访问点。文中提到了两种实现单例模式的方法——饥汉模式(预先创建实例)和懒汉模式(按需创建实例),并讨论了它们在单线程和多线程环境下的安全性。在多线程环境中,未加锁的懒汉模式可能导致创建多个实例,而通过引入互斥量可以解决这个问题,但会带来效率损失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、简介

单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。

二、应用场景

 希望某个类只产生一个实例化对象,如:windows的回收站,任务管理器等不能多开,产生多个窗口。

三、两种方式实现单例模式

类的实例化方式:1.构造函数  2.拷贝构造函数

我们将其设置为私有方法,便可以防止其在类外创建实例化对象。

将构造函数设置为私有方法,并不会影响静态成员在类外创建,因为他们同属于一个类域,可以访问类的所有成员。

1.饥汉模式:不管需不需要用,提前创建好对象

方法一:

class Int
{
private:
    int value;
    static Int obj;   //静态对象  存储在数据区
private:
    Int(int x = 0) :value(x) { cout << "Create Int : " << this << endl; }
    Int(const Int& it) = delete;  //删除拷贝构造
    Int& operator=(const Int& s) = delete;//删除赋值

public:

    ~Int() { cout << "Destroy Int: " << this << endl; }

    int& Value() { return value; }
    const int& Value() const { return value; }
    void Print() const { cout << value << endl; }
    static Int& getInt()  //静态方法访问静态成员
    {
        return Int::obj;
    }
};
Int Int::obj(10);    

int main()

{

Int&  a=Int::getInt();

return 0;

}

方法二:

class Int
{
private:
    int value;
private:
    Int(int x = 0) :value(x) { cout << "Create Int : " << this << endl; }
    Int(const Int& it) = delete;  //删除拷贝构造
    Int& operator=(const Int& s) = delete;//删除赋值

public:

    ~Int() { cout << "Destroy Int: " << this << endl; }

    int& Value() { return value; }
    const int& Value() const { return value; }
    void Print() const { cout << value << endl; }
    static Int& getInt(int x=10)  //静态方法访问静态成员
    {

        static Int obj(x);    //静态对象  存储在数据区
        return  obj;
    }
};

int main()

{

Int&  a=Int::getInt();

return 0;

}

2.懒汉模式:用的时候在通过new申请

class Object
{
private:
    int value;
    static Object* pobj;
private:
    Object(int x = 0) :value(x) {
        cout << "Create Object" << this << endl;
    }
    Object(const Object&) = delete;
    Object& operator=(const Object&) = delete; // C++ 11;
public:
    ~Object() { cout << "Destroy Object" << this << endl; }
    int& Value() { return value; }
    const int& Value()const { return value; }
    void show() const { cout << "value: " << value << endl; }
    static Object* GetObject(int x)
    { 
       if (nullptr == pobj)
        {
            pobj = new Object(x);  // .heap
        }
            return pobj;
    }
};
Object* Object::pobj = nullptr;
int main()
{
    Object* pobja = Object::GetObject(100);
    return  0;
}

三、单例模式和单线程  

单线程:单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。(ps : 一心一意的痴汉)

1.饥汉模式:

方法一,方法二都是安全的,不会多次重复构建。

2.懒汉模式:

上述方法也是安全的。

 四、单例模式和多线程

1.饥汉模式:

上述方法一是安全的,因为静态成员在线程执行前已经创建。

2.懒汉模式:

上述方法种添加测试代码:

void funa()
{
    Int* pa = Int::getInt(50);
    pa->Print();
 }
void funb()
{
    Int* pb = Int::getInt(25);
    pb->Print();
}
int main()
{
    thread tha(funa);
    thread thb(funb);
    tha.join();
    thb.join();
    return 0;
}
 

 测试结果:

我们发现多线程模式下创建了多个对象,这不符合我们只实例化一个实体的要求。

我们可以进行以下修改:

#include <iostream> 
#include <thread>
#include <mutex> //互斥量

class Int
{
private:
    int value;
    static Int* pobj ; 
    static mutex mutex_;
private:
    Int(int x = 0) :value(x) { cout << "Create Int : " << this << endl; }
    Int(const Int& it) = delete;
    Int& operator=(const Int& s) = delete;

public:

    ~Int() { cout << "Destroy Int: " << this << endl; }

    int& Value() { return value; }
    const int& Value() const { return value; }
    void Print() const { cout << value << endl; }
    static Int* getInt(int x=10)
    {
        std::unique_lock<std::mutex> lock(mutex_); 

         //加锁,确保一个进程实例化对象结束后,其他进程才能进入
        if (nullptr == pobj)
        {
            pobj = new Int(x);
        }
        return  pobj;
    }
};
Int* Int::pobj = nullptr;
std::mutex Int::mutex_;
void funa()
{
    Int* pa = Int::getInt(50);
    pa->Print();
 }
void funb()
{
    Int* pb = Int::getInt(25);
    pb->Print();
}
int main()
{
    thread tha(funa);
    thread thb(funb);
    tha.join();
    thb.join();
    return 0;
}

 但是加锁之后,仍然存在效率问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值