Effective C++读书笔记(3)(二)

2014-11-24 12:20:03 · 作者: · 浏览: 5
extern FileSystem tfs; //预备给客户使用的对象,tfs代表"the file system"
现在假设某些客户建立了一个class用以处理文件系统内的目录(directories)。很自然他们的class会用上theFileSystem对象:

1. class Directory { //由程序库客户建立
2. public:
3. Directory( params );
4. ...
5. };
6. Directory::Directory( params )
7. {
8. ...
9. std::size_t disks = tfs.numDisks();//使用tfs对象
10. ...
11. }
进一步假设,这些客户决定创建一个Directory对象,用来放置临时文件:

1. Directory tempDir( params ); //为临时文件而做出的目录
除非tfs在tempDir之前先被初始化,否则tempDir的构造函数会用到尚未初始化的tfs。但tfs和tempDir是不同的人在不同的时间于不同的源码文件建立起来的,它们是定义于不同编译单元内的non-local static对象。

C++ 对"定义于不同的编译单元内的non-localstatic对象"的初始化相对次序并无明确定义。这是有原因的:决定它们的初始化次序相当困难,非常困难,根本无解。

一个小小的设计便可完全消除这个问题:将每个non-localstatic对象搬到自己的专属函数内,并将该对象在此函数内被声明为static,这些函数返回一个reference指向它所含的对象。然后用户调用这些函数,而不直接指涉这些对象。换句话说,non-local static对象被local static对象替换了。这是Singleton模式的一个常见实现手法。

C++ 保证,函数内的local static对象会在该函数被调用期间首次遇上该对象之定义式时被初始化。如果你从未调用non-local static对象的"仿真函数",就绝不会引发构造和析构成本!

以此技术施行于tfs和tempDir身上,结果如下:

1. class FileSystem { ... }; //同前
2. FileSystem& tfs() //这个函数用来替换tfs对象;它在
3. { //FileSystem class中可能是个static。
4. static FileSystem fs; //定义并初始化一个local static对象,
5. return fs; //返回一个reference指向上述对象。
6. }
7. class Directory { ... }; //同前
8. Directory::Directory( params )//同前,但原本的reference to tfs
9. { //现在改为tfs()
10. ...
11. std::size_t disks = tfs().numDisks( );
12. ...
13. }
14. Directory& tempDir() //这个函数用来替换tempDir对象;
15. { //它在Directory class中可能是个static。
16. static Directory td; //定义并初始化local static对象,
17. return td; //返回一个reference指向上述对象。
18. }
这么修改之后,这个系统程序的客户唯一不同的是他们现在使用tfs()和tempDir()而不再是tfs和tempDir,也就是说他们使用函数返回的"指向static对象"的references,而不再使用static对象自身。这些函数内含static对象的事实使它们在多线程系统中带有不确定性。

l 为免除"跨编译单元之初始化次序"问题,请以local static对象替换non-local static对象。


摘自 pandawuwyj的专栏