c++单例模式

// 单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点
// 在c++中,单例模式可以通过类的静态成员变量和静态成员函数实现,构造函数为私有成员函数
// 1.只有一个实例,即全局唯一
// 2.可以在程序的任何地方访问

// 1.线程安全问题:
// 如果多个线程同时调用getInstance()函数,可能会导致多个实例被创建
// 为了解决这个问题,可以使用线程安全的实现方式,例如使用互斥锁或原子操作来保证只有一个线程可以创建实例
// 2.内存泄漏问题:
// 如果单例对象没有正确的被销毁,可能导致内存泄漏
// 为了避免这个问题,可以在单例类中添加析构函数来释放资源
// 3.可维护性问题:
// 单例模式可能会导致代码的可维护性变差,因为它将对象的创建和访问耦合在一起

// 应用场景:
// 适用于全局唯一的对象场景,入日志系统,配置文件管理器等
#include <iostream>
#include <string>

using namespace std;

class Logger {
public:
    // 1. 将 `getInstance` 定义为静态成员函数即可在不创建对象的情况下调用;
    // 2. 如果需要使用该类的实例,可以将成员函数定义为非静态成员函数,并创建实例来调用该函数;
    // 3. 如果不需要使用该类的实例,推荐将 Logger 设计为一个只包含静态成员函数的单例类,以避免对象创建的开销和错误使用。
    // 静态局部变量instance用于存储单例,这保证了在程序运行期间只有一个单例被创建
    static Logger & getInstance() {
        static Logger instance;
        return instance;
    }
    void log(const std::string &message) {
        m_log += message;
        std::cout << "log:\n" << m_log << std::endl;
    }
private:
    // 构造函数私有化,防止外部创建实例
    Logger() {}
    ~Logger() {}
    // 禁止使用拷贝构造函数创建Logger的副本对象
    // =delete的含义是显示删除,可以用于禁止某些函数的使用
    // 包括默认的拷贝构造/移动构造/拷贝赋值运算符/移动赋值运算符等
    // 这个特性可以确保代码的正确性和安全性
    Logger(const Logger &) = delete;
    // 禁止使用拷贝赋值运算符来复制Logger的对象
    Logger & operator = (const Logger &) = delete;
    std::string m_log;
};

int main()
{
    // 1. 将 `getInstance` 定义为静态成员函数即可在不创建对象的情况下调用;
    // 所有信息都打印到一个对象上,就是单例模式的体现
    Logger &log1 = Logger::getInstance();
    log1.log("aaaaa\n");
    Logger &log2 = Logger::getInstance();
    log2.log("bbbbb\n");
    Logger::getInstance().log("ccccc\n");
    Logger::getInstance().log("ddddd\n");
    return 0;
}
#include <iostream>
#include <string>

using namespace std;


// 定义一个单例模式的任务队列
class TaskQueue {
public:
    // 静态成员函数可以通过对象、类名、类的对象指针和类的对象引用进行访问,因为静态成员函数是和类相关但和对象无关的。
    // 可以使用对象名.`静态成员函数名`、类名.`静态成员函数名`、对象指针名->`静态成员函数名` 和对象引用.`静态成员函数名` 的方式访问。
    // 非静态成员函数不能直接通过类来访问,因为非静态成员函数是与对象关联的,需要通过对象或对象指针/引用来调用。
    // 可以使用对象名.`非静态成员函数名`、对象指针名->`非静态成员函数名` 和对象引用.`非静态成员函数名` 的方式访问。
    // 因为非静态成员函数中可能会访问对象的状态,而类无法代表一个具体的对象,所以不能直接通过类来访问非静态成员函数。
    static TaskQueue *getInstance() {
        if (m_taskQ == nullptr)
        {
            m_taskQ = new TaskQueue();
        }
        return m_taskQ;
    }
    void print() {
        std::cout << "this is a singleton member..." << std::endl;
    }
private:
    // 为了不能再外边创建该类的任何对象,需要显示的删除掉构造函数,拷贝构造函数以及对象赋值
    TaskQueue() = default;
    TaskQueue(const TaskQueue &) = delete;
    TaskQueue & operator = (const TaskQueue &) = delete;
    // 只能通过类名访问静态属性或方法
    static TaskQueue *m_taskQ;
};

// 静态变量必须再类外边进行初始化,不能再类里边进行初始化
TaskQueue *TaskQueue::m_taskQ = new TaskQueue();

int main()
{
    TaskQueue *task = TaskQueue::getInstance();
    task->print();
    TaskQueue::getInstance()->print();

    return 0;
}
// 单例模式
// 应用场景:
// 配置管理,日志记录,线程池,连接池,对象池,消息队列

// 实现步骤:
// 1.将类的构造方法定义为私有方法
// 2.定义一个私有类的静态实例,保存一个全局唯一的静态实例
// 3.提供一个共有的获取实力的静态方法

// 知识点:
// 1.static静态成员数据
// 2.static静态成员函数
// 3.template模板类
// 4.fridnd友元类

#include <iostream>
#include <string>

using namespace std;

class A {
public:
    static A *instance() {
        if (m_instance == nullptr)
        {
            m_instance = new A();
        }
        return m_instance;        
    }
    void show() {
        std::cout << m_name << std::endl;
    }
private:
    A() : m_name("A") {}
    ~A() {}
    A(const A &) = delete;
    A & operator = (const A &) = delete;
private:
    std::string m_name;
    static A * m_instance;
};

// 静态成员和静态成员函数需要在类外初始化
// 注意需要加上作用域运算符A::,表示该静态成员数以类A
A * A::m_instance = nullptr;

int main()
{
    A::instance()->show();

    return 0;
}
#include <iostream>
#include <string>

namespace utility {
namespace singleton {
template <typename T>
class Singleton {
public:
    static T *instance() {
        if (m_instance == nullptr)
        {
            m_instance = new T();
        }
        return m_instance;
    }
private:
    Singleton() {}
    ~Singleton() {}
    Singleton(const Singleton<T> &) = delete;
    Singleton<T> & operator = (const Singleton<T> &) = delete;
private:
    static T *m_instance;
    std::string m_name;
};

// 模板的特殊写法,类的静态成员需要再类外初始化
template <typename T>
T * Singleton<T>::m_instance = nullptr;

}
}


class A {
    // 声明Singleton这个模板类为A类一个友元类,模板参数为A
    friend class utility::singleton::Singleton<A>;
public:
    void show() {
        std::cout << m_name << std::endl;
    }
private:
    A() : m_name("A") {}
    ~A() {}
    A(const A &) = delete;
    A & operator = (const A &) = delete;

private:
    std::string m_name;
};

class B {
    // 声明Singleton这个模板类为A类一个友元类,模板参数为B
    friend class utility::singleton::Singleton<B>;
public:
    void show() {
        std::cout << m_name << std::endl;
    }
private:
    B() : m_name("B") {}
    ~B() {}
    B(const B &) = delete;
    B & operator = (const B &) = delete;

private:
    std::string m_name;
};

int main()
{
    utility::singleton::Singleton<A>::instance()->show();
    utility::singleton::Singleton<B>::instance()->show();
    // 关于线程安全问题,可以通过全局只创建一次进行全局调用的方式规避线程安全问题
    // 避免引入繁琐的机制导致程序维护变得困难
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值