单例模式:保证只能产生一个实例
初步了解单例
c++简单单例源码:
#include <iostream>
class singleton
{
private:
//构造
singleton(void)
{
std::cout << "create singleton ." << std::endl;
}
static singleton *m_singleton;
public:
//析构
~singleton(void)
{
std::cout << "delete singleton ." << std::endl;
}
void foo(void)
{
std::cout << "singleton::foo this : " << this << std::endl;
}
//获取实例
static singleton *get_instance(void)
{
if(m_singleton == nullptr)
{
m_singleton = new singleton();
}
return m_singleton;
}
//释放实例
static void destroy_instance(void)
{
if(m_singleton)
{
delete m_singleton;
m_singleton = nullptr;
}
}
};
singleton *singleton::m_singleton = nullptr;
int main()
{
std::cout << "start-up .." << std::endl;
singleton *s1 = singleton::get_instance();
s1->foo();
singleton *s2 = singleton::get_instance();
s2->foo();
singleton::destroy_instance();
std::cout << "done .." << std::endl;
return 0;
}
运行结果:
问题一
main函数代码改成这个样子
int main()
{
std::cout << "start-up .." << std::endl;
singleton *s1 = singleton::get_instance();
s1->foo();
singleton *s2 = singleton::get_instance();
s2->foo();
singleton s3(*s1);
s3.foo();
singleton::destroy_instance();
std::cout << "done .." << std::endl;
return 0;
}
运行结果
c++会有默认拷贝赋值、拷贝构造、移动构造,都会造成单例不唯一的现象
代码改造:
#include <iostream>
class singleton
{
private:
//构造
singleton(void)
{
std::cout << "create singleton ." << std::endl;
}
//拷贝构造
singleton(const singleton &)
{
}
//移动 c++11
singleton(singleton &&)
{
}
//拷贝赋值
singleton &operator=(const singleton &)
{
}
//移动 c++11
singleton &operator=(singleton &&)
{
}
//析构
~singleton(void)
{
std::cout << "delete singleton ." << std::endl;
}
static singleton *m_singleton;
public:
void foo(void)
{
std::cout << "singleton::foo this : " << this << std::endl;
}
//获取实例
static singleton *get_instance(void)
{
if(m_singleton == nullptr)
{
m_singleton = new singleton();
}
return m_singleton;
}
//释放实例
static void destroy_instance(void)
{
if(m_singleton)
{
delete m_singleton;
m_singleton = nullptr;
}
}
};
singleton *singleton::m_singleton = nullptr;
int main()
{
std::cout << "start-up .." << std::endl;
singleton *s1 = singleton::get_instance();
s1->foo();
singleton *s2 = singleton::get_instance();
s2->foo();
//singleton s3(*s1);
//s3.foo();
singleton::destroy_instance();
std::cout << "done .." << std::endl;
return 0;
}
这样就避免了,不经意间导致单例非单例的情况。
问题二:
刚刚的代码多线程的情况下可能会出现new两次的情况
使用c++11局部静态变量
#include <iostream>
class singleton
{
private:
//构造
singleton(void)
{
std::cout << "create singleton ." << std::endl;
}
//拷贝构造
singleton(const singleton &)
{
}
//移动
singleton(singleton &&)
{
}
//拷贝赋值
singleton &operator=(const singleton &)
{
}
//移动
singleton &operator=(singleton &&)
{
}
//析构
~singleton(void)
{
std::cout << "delete singleton ." << std::endl;
}
static singleton *m_singleton;
public:
void foo(void)
{
std::cout << "singleton::foo this : " << this << std::endl;
}
//获取实例
static singleton *get_instance(void)
{
static singleton s_singleton;
return &s_singleton;
}
};
int main()
{
std::cout << "start-up .." << std::endl;
singleton *s1 = singleton::get_instance();
s1->foo();
singleton *s2 = singleton::get_instance();
s2->foo();
//singleton s3(*s1);
//s3.foo();
std::cout << "done .." << std::endl;
return 0;
}
如果是c++11之前的版本,静态对象线程会不安全,那如何解决
#include <iostream>
class singleton
{
private:
//构造
singleton(void)
{
std::cout << "create singleton ." << std::endl;
}
//拷贝构造
singleton(const singleton &)
{
}
//移动
singleton(singleton &&)
{
}
//拷贝赋值
singleton &operator=(const singleton &)
{
}
//移动
singleton &operator=(singleton &&)
{
}
//析构
~singleton(void)
{
std::cout << "delete singleton ." << std::endl;
}
static singleton * volatile m_singleton;
static pthread_mutex_t mutex;
public:
void foo(void)
{
std::cout << "singleton::foo this : " << this << std::endl;
}
//获取实例
static singleton *get_instance(void)
{
//这样写保证已经创建成功后不需要再调用锁导致效率低下的问题
if(m_singleton == nullptr)
{
pthread_mutex_lock(&mutex);
if(m_singleton == nullptr)
{
//非c++11 new singleton()会返回未初始化的地址 多线程访问的时候就出现操作未初始化的内存空间
//所以使用局部变量保证初始化完成后,m_singleton才有值
//防止被编译器优化 使用volatile
singleton *temp = new singleton();
m_singleton = temp;
}
pthread_mutex_unlock(&mutex);
}
return m_singleton;
}
//释放实例
static void destroy_instance(void)
{
if(m_singleton)
{
delete m_singleton;
m_singleton = nullptr;
}
}
};
singleton * volatile singleton::m_singleton = nullptr;
pthread_mutex_t singleton::mutex = PTHREAD_MUTEX_INITIALIZER;
int main()
{
std::cout << "start-up .." << std::endl;
singleton *s1 = singleton::get_instance();
s1->foo();
singleton *s2 = singleton::get_instance();
s2->foo();
//singleton s3(*s1);
//s3.foo();
singleton::destroy_instance();
std::cout << "done .." << std::endl;
return 0;
}
c++11还有atomic类原子操作可以实现
c++11已经没有这种问题,使用atomic实现就没有什么必要了
懒汉
即在需要的时候,才创建对象
上述代码就是懒汉模式
饿汉
饿汉:即类产生的时候就创建好实例对象
饿汉没有线程安全问题