36. 00035:
37. 00036: static singleton2_t instance_;
38. 00037: };
39. 00038:
40. 00039: singleton2_t singleton2_t::instance_;
41. 00040: singleton1_t singleton1_t::instance_;
42. 00041:
43. 00042: int main ()
44. 00043: {
45. 00044: (void) singleton2_t::instance ();
46. 00045: cout << "count = " << singleton1_t::instance ()-
>count () << endl;
47. 00046: return 0;
48. 00047: }
图 1
图中的两个类在实现 singleton 时都将类的构造和析构函数的对外可视性设为
private,这是实现 singleton 首先要注意的一个点。通过这一手段,有助于预
防他人粗心地定义类实例。
图中的 singleton2_t 类在其构造函数中调用 singleton1_t 类的
count_increase ()方法使计数加一。第 44 行的代码用于代表使用
singleton2_t 实例。第 46 行代码则显示 singleton1_t 类的记数信息。图
2 示例了该程序的运行结果。
1.
$ g++ main.cpp -o singleton.exe
2.
$ ./singleton.exe
3. count = 0
图 2
是不是对于最终的显示计数为 0 而不是 1 感到奇怪?错误发生的原因在于,
singleton2_t 类实例的构造是先于 singleton1_t 类的,当
singleton1_t 类的实例在最后构造时会把 count_变量置成 0,从而覆盖
singleton2_t 的构造函数所引起的变更。
尽管这是一个精心设计的错误,但在大型项目中出现这类错误的可能性却并
不小。因为在现实项目中,singleton1_t 和 singleton2_t 两个类的实现
很可能是在不同的源文件中,这势必造成两个类实例的初始化顺序会因链接
顺序不同而不同,《揭示 C++中全局类变量的构造与析构顺序》一文介绍了这
是为什么。
在本例中,如果将第 39 行和第 40 行的代码进行对调就不会出现这种奇怪的
现象,但这不是解决问题的终极方法。更好的方法需要更改 singleton 的实
现方法,图 3 示例了一种新的实现方法。