Day4 单例类

设计模式: 代码的一种写法,程序灵活,维护方便,但不便于别人理解。

单例设计模式:单例:项目中某个类只能创建一个对象(静态对象),单例类如下:

#include<iostream>
using namespace std;

class A{
private:
	A(){}        //将构造函数声明为私有,防止生成多个对象
	static A *a;     
public:
	static A* get_instance() {   //
		if (A::a == NULL) {
			A::a = new A();
			static B b;   //生成这个类中类B的对象,用于销毁静态指针a
		}
		return A::a;
	}
	class B {
	public:
		~B() {
			if (A::a != NULL) {
				delete A::a;
				A::a = NULL;        //防止野指针
			}
		}
	};
};
A* A::a = NULL;      //定义(初始化)静态成员变量,不然使用起来会报错。


int main() {
	A *b = A::get_instance();

	return 0;
}

关于为何不直接写析构函数:

        一:由于A::a是静态成员指针,由我们自己new出来的,所以在程序运行结束并不会调用析构函数,所以手写析构函数delete A::a是不可行的。

        二:如果写析构函数(在里面delete A::a;)后主动调用析构函数的话,会使得程序一直在调用析构函数和delete中循环,因为调用delete会调用析构函数,调用析构函数又会delete。

正确方法如上:在开辟a的内存空间时声明类中类B的静态对象B::b(不加静态的话就变成局部变量就没用了),并手写B类的析构函数(在里面delete A::a),这样在B::b的生命周期结束时会调用B的析构函数。

在多线程中,上述单例类还需要继续改进,不然可能会导致其变为非单例类(多个线程同时new了A::a)。

        法一:直接加锁,直观,但是效率太低,不推荐;

mutex mymutex;         //注意,互斥量要定义为全局变量,不然不能在静态成员函数中使用。

class A{
private:
	A(){}        //将构造函数声明为私有,防止生成多个对象
	static A *a;     
public:
	static A* get_instance() {   
        unique_lock<mutex> lock1(mymutex);    //加锁
		if (A::a == NULL) {
			A::a = new A();
			static B b;   //生成这个类中类B的对象,用于销毁静态指针a
		}
		return A::a;
	}
	class B {
	public:
		~B() {
			if (A::a != NULL) {
				delete A::a;
				A::a = NULL;        //防止野指针
			}
		}
	};
};
A* A::a = NULL;

        法二:双重锁定(双重检查),效率比法一高,常见用法。

mutex mymutex;         //注意,互斥量要定义为全局变量,不然不能在静态成员函数中使用。

class A{
private:
	A(){}        //将构造函数声明为私有,防止生成多个对象
	static A *a;     
public:
	static A* get_instance() {  
		if (A::a == NULL) { 
            unique_lock<mutex> lock1(mymutex);    //加锁
		    if (A::a == NULL) {
			    A::a = new A();
			    static B b;   //生成这个类中类B的对象,用于销毁静态指针a
		    }
        }
		return A::a;
	}
	class B {
	public:
		~B() {
			if (A::a != NULL) {
				delete A::a;
				A::a = NULL;        //防止野指针
			}
		}
	};
};
A* A::a = NULL;

        法三:使用函数call_once(参数一, 参数二),参数一是一个once_flag结构的对象,参数二是一个函数,该函数通过参数一记录的状态确保其第二个参数代表的函数只被调用一次。call_once消耗的资源较少,效率比互斥量要高一些。在头文件<mutex>中。

mutex mymutex;         //注意,互斥量要定义为全局变量,不然不能在静态成员函数中使用。
once_flag g_flag;      //注意,结构体要定义为全局变量,不然不能在静态成员函数中使用。
class A {
private:
	A() {}        //将构造函数声明为私有,防止生成多个对象
	static A* a;
public:
	static void dingyi() {   //注意是静态成员函数
		if (A::a == NULL) {
			A::a = new A();
			static B b;   //生成这个类中类B的对象,用于销毁静态指针a
		}
	}
	static A* get_instance() {
		call_once(g_flag, dingyi);    //保证只定义一次,若多个线程同时到这,会和互斥量一样阻塞,保证一个线程一个线程地过去。
		return A::a;
	}
	class B {
	public:
		~B() {
			if (A::a != NULL) {
				delete A::a;
				A::a = NULL;        //防止野指针
			}
		}
	};
};
A* A::a = NULL;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值