c++中static单例模式
在《C++中的static》一文中,提到了局部的static声明变量,可以保证对象只被初始化一次,这种方式可以用来写单例模式。由于函数返回过程中会可能发生对象复制的情况,导致原本希望获得单例对象,最后却不如所愿,所以写单例模式的时候需要注意下,避免这种情况发生。
那么应该如何正确使用static写单例模式呢?
函数返回值与对象复制
C++函数返回值类型,接收变量的类型会影响函数返回过程中是否会发生对象的复制。
当函数返回值不是引用类型是,会发生复制。
返回非引用类型 1
2
3
4
5
6
7static Student GetInstance() {
static Student stu;
return stu;
}
Student s1 = Student::GetInstance(); // 会复制
Student& s2 = Student::GetInstance(); // 异常,不能用引用类型接收返回值当函数返回值是引用类型,接收函数返回值的变量不是引用时,仍然发生复制;函数返回值是引用类型,接收函数返回值的变量是引用类型,不会发生复制
返回引用类型 1
2
3
4
5
6
7static Student& GetInstance() {
static Student stu;
return stu;
}
Student s1 = Student::GetInstance(); // 仍然会复制
Student& s1 = Student::GetInstance(); // 无复制
当你用上面第二种方式写单例,使用时候要特别注意,不要去用一个非引用的变量去接收返回值,否者往往出现不期望得到的结果。
单例错误的写法
1 |
|
输出结果
stu 0x55d80ed86040
stu 0x55d80ed86040
stu 0x55d80ed86040
stu1 0x7ffdd71828f0
stu2 0x7ffdd7182920
stu3 0x7ffdd7182950
可以看出使用GetInstance()
获得的stu1,stu2,stu3
并没有如愿以偿获得到单例的Student对象,上面代码中实际上每一次调用GetInstance()
执行static Student stu;
实际上只构建了一次对象,但是在对象返回时候由于发生了复制,最终接收到的都是重新构建的对象。
返回指针的方式
1 |
|
输出结果
stu1 0x556c9c248040
stu2 0x556c9c248040
stu3 0x556c9c248040
这样做有个缺陷,因为调用者如果使用delete instance
会导致对象被提前销毁。
所以建议使用返回引用的方式。
返回引用的方式
1 |
|
注意,实例中为了避免调用者使用非引用的变量去接收返回值,将拷贝构造函数标记=delete
, 禁止调用。
1 | Student(const Student&) = delete; |
综上所述,建议使用最后提到的返回引用的方式来创建单例模式。