单例模式

一. static 关键字
1. 类中静态变量和静态成员函数
  • 1):类的静态成员:
  • ①:静态成员变量属于整个类所有
  • ②:静态成员变量的生命期不依赖于任何对象,为程序的生命周期
  • ③:可以通过类名直接访问公有静态成员变量
  • ④:所有对象共享类的静态成员变量
  • ⑥:可以通过对象名访问公有静态成员变量
  • ⑦:静态成员变量需要在类外单独分配空间
  • ⑧:静态成员变量在程序内部位于全局数据区
  • 2):类的静态成员函数:
  • 类的静态成员函数有如下特性:
  • ①:静态成员函数是类的一个特殊的成员函数
  • ②:静态成员函数属于整个类所有,没有this指针
  • ③:静态成员函数只能直接访问静态成员变量和静态成员函数,因为没有this指针
  • ④:可以通过类名直接访问类的公有静态成员函数
  • ⑥:可以通过对象名访问类的公有静态成员函数
  • ⑦:定义静态成员函数,直接使用static关键字修饰即可

#include <iostream>
using namespace std;

class testStatic {
public:
	//定义一个公有的静态成员
	static int pub_value;
    testStatic() {};
    ~testStatic() {};
    //定义类的静态成员函数
    static void pub_Print() {
        cout << pub_value << endl;
    }
    static void pri_Print() {
        cout << pri_value << endl;
    }
//定义类的静态成员变量
private:
    static int pri_value;
};

//类的静态成员需要在类外分配内存空间以及初始化。
//如果不初始化,则为0
int testStatic::pri_value = 100;
int testStatic::pub_value = 100;

int main() {
	auto ptr = new testStatic();
    cout << ptr->pub_value << endl;
    ptr->pri_Print();
    ptr->pub_Print();
    testStatic::pri_Print();
    testStatic::pub_Print();
    return 0;
}

输出:
100
100
100
100
100
二. 单例模式

敖 丙

  • 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  • 主要解决:一个全局使用的类频繁地创建与销毁。
  • 何时使用:当您想控制实例数目,节省系统资源的时候。
  • 如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
  • 关键代码:构造函数是私有的。静态成员函数返回该实例。
  • 实例:一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。windows 系统中只能有一个窗口管理器,某个程序中只能有一个日志输出系统等。
  • 优点:
  • ①:在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  • ②:避免对资源的多重占用(比如写文件操作)。
  • 缺点:
  • ①:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
  • 使用场景:
  • ①:要求生产唯一序列号。
  • ②:WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
  • ③:创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
  • 注意事项:getInstance()方法中需要使用同步锁 synchronized (Singleton.class)防止多线程同时进入造成 instance 被多次实例化。
  • 创建线程安全的单例有那些实现方法?

1. 饿汉模式:
  • 特点:一开始就初始化单例对象,不管需要不需要
  • 优点以及缺点:
  • 不用担心多线程问题;
  • 可能程序中不需要这个单例对象,如果对象大的话,造成不嫩那个忍受的浪费。
#include <iostream>
#include <thread>
#include <vector>
using namespace std;

//饿汉模式
class hunSingleton{
public:
    //静态公有成员函数,获取单例对象
    static hunSingleton* getInstance() {
        return &hSingleton;
    }
    void print() {
        cout << "Print is called" << endl;
    }
private:
    //构造函数为私有函数
    hunSingleton(){
        cout << "hunSingleton is called" << endl;
        hunSingleton::getInstance();
    };
    //私有static单例对象
    static hunSingleton hSingleton;
};

hunSingleton hunSingleton::hSingleton;

void fun1() {
    auto p = hunSingleton::getInstance();
    p->print();
}

int main() {
    auto ptr1 = hunSingleton::getInstance();
    auto ptr2 = hunSingleton::getInstance();
    cout << (ptr1==ptr2?"true":"false") << endl;
    vector<thread> threadPool;
    for(int i = 0; i < 10; i++) {
        threadPool.push_back(thread(fun1));
    }
    for(auto &ptr: threadPool) {
        ptr.join();
    }
    return 0;
}
//输出:
hunSingleton is called
true
Print is called
Print is called
Print is called
Print is called
Print is called
Print is called
Print is called
Print is called
Print is called
Print is called
2. 懒汉模式:
  • 特点:不创建单例对象直到需要这个单例对象。
  • 优点以及缺点:
  • 不会造成资源浪费,如果不需要创建单例对象;
  • 但是多线程编程较为复杂。
#include <vector>
#include <thread>
#include <iostream>
#include <mutex>
using namespace std;

//懒汉模式
class lazySingleton{
public:
    void print() {
        cout << "print is called" << endl;
    }
    static lazySingleton* getInstance() {
        if(lazyST_ == nullptr) {
            std::lock_guard<std::mutex> lock(mu_);
            if(lazyST_ == nullptr) {
                lazyST_ = new lazySingleton();
            }
        }
        return lazyST_;
    }
private:
    static std::mutex mu_;
    static lazySingleton* lazyST_;
    lazySingleton() {
        cout << "lazySingleton is called" << endl;
    };
};

std::mutex lazySingleton::mu_;
lazySingleton* lazySingleton::lazyST_ = nullptr;

void func2() {
    auto* ptr = lazySingleton::getInstance();
    ptr->print();
}

int main() {
    vector<thread> threadPool;
    for(int i = 0; i < 10; i++) {
        threadPool.push_back(thread(func2));
    }
    for(auto &p: threadPool) {
        p.join();
    }
    return 0;
}
//输出
lazySingleton is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
3. C++11 简化版
  • 可以利用 C++11 对 static 的改进性质简化代码。
  • static变量本身全局就只有一份,与单例对象的性质极其相似。而C++11为了确保只初始化static变量一次,提供了两段检查锁机制(在上述代码的汇编代码中,可以清楚地看到两段检查锁的逻辑)。换言之,C++11对于static变量,自带使用了单例模式,自然不用我们再费事。
#include <iostream>
#include <vector>
#include <thread>
using namespace std;

class singleton{
public:
    static singleton* getInstance() {
        static singleton ptrST_;
        return &ptrST_;
    }
    void print() {
        cout << "print is called" << endl;
    }
private:
    singleton (){
        cout << "singleton is called" << endl;
    }
};

void func() {
    auto ptr = singleton::getInstance();
    ptr->print();
}

int main() {
    vector<thread> threadPool;
    for(int i = 0; i < 10; i++) {
        threadPool.push_back(thread(func));
    }
    for(auto &p: threadPool) {
        p.join();
    }
    return 0;
}
//输出
singleton is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
print is called
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值