background image

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 

图 

是不是对于最终的显示计数为 0 而不是 1 感到奇怪?错误发生的原因在于,
singleton2_t 类实例的构造是先于 singleton1_t 类的,当
singleton1_t 类的实例在最后构造时会把 count_变量置成 0,从而覆盖
singleton2_t 的构造函数所引起的变更。

尽管这是一个精心设计的错误,但在大型项目中出现这类错误的可能性却并
不小。因为在现实项目中,singleton1_t 和 singleton2_t 两个类的实现
很可能是在不同的源文件中,这势必造成两个类实例的初始化顺序会因链接
顺序不同而不同,《揭示 C++中全局类变量的构造与析构顺序》一文介绍了这
是为什么。

在本例中,如果将第 39 行和第 40 行的代码进行对调就不会出现这种奇怪的
现象,但这不是解决问题的终极方法。更好的方法需要更改 singleton 的实
现方法,图 3 示例了一种新的实现方法。