对单例模式的一个简单思考
测试代码如下:
#include <iostream> class TestSingleton { public: ~TestSingleton() { std::cout << "TestSingleton " << m_i << " destructor\n"; } static TestSingleton& getInstance(int i) { static TestSingleton ts(i); return ts; } private: TestSingleton(int i):m_i(i) { std::cout << "TestSingleton " << m_i << " constructor\n"; } int m_i; }; int main() { TestSingleton& ts1 = TestSingleton::getInstance(1); TestSingleton& ts2 = TestSingleton::getInstance(2); }
代码很简单,最终的结果怎样呢?
我原本以为1和2都会输出的,因为两次分别调用getInstance时用的是不一样的参数,所以应该会实例出两个不一样的TestSingleton对象吧,最终的结果和我料想的有所不同:
只构造出了参数为1的singleton对象,并没与改造出参数为2的对象,这是为什么呢?仔细思考了一下,然后就顿悟了,哎,原因还是出了对static关键字的理解不深,这么快就忘记了。
在函数体中,如果声明了一个static变量,不管进入这个函数多少次,该static变量只会被初始化一次。
所以当我第二次调用getInstance函数时,进入getInstance后直接就跳过了TestSingleton的初始化语句,也就是TestSingleton的构造函数,因此最终得到的TestSinglon对象和上次的是同一个。我打断点调试的时候发现确实如此。
从这里我收获了一个小小的道理,单例模式的构造函数不应该传参,如果需要传参的话,这个类就应该被设计为普通类。因为如果需要传参的话,就很根据不同的参数生成不同的类的实例,与单例类“一个类只存在一个对象”的设定不符。
其实道理与下面这个是相似的。
void fun(int i) { static int m(i); std::cout << m << "\n"; } int main() { fun(1); fun(2); }
最终两次的输出结果依然都是1,因为m只被初始化一次。
void fun(int i) { static int m = i; std::cout << m << "\n"; } int main() { fun(1); fun(2); }
最终的输出仍然为两个1,这段和上段代码有点类似于 类的拷贝构造和赋值构造 都是”构造函数”。
void fun(int i) { static int m; m = i; std::cout << m << "\n"; } int main() { fun(1); fun(2); }
这样的话输出结果就变成一个1和一个2了。