我正在阅读Scott Meyer的Effective C++的第4项,他试图显示一个示例,其中在不同的翻译单元之间使用静态非本地对象。他强调了一个问题,即一个翻译单元中使用的对象在使用之前不知道是否已在另一翻译单元中对其进行了初始化。第三版的第30页,以防有人复制。
例子是这样的:
一个文件代表一个库:
class FileSystem{
public:
std::size_t numDisks() const;
....
};
extern FileSystem tfs;
并在客户端文件中:
class Directory {
public:
Directory(some_params);
....
};
Directory::Directory(some_params)
{
...
std::size_t disks = tfs.numDisks();
...
}
因此,我的两个问题是:
1)如果客户端代码需要使用
tfs
,则将包含某种include语句。因此,确定此代码是一个翻译单元中的全部吗?我看不到如何引用不同翻译单元中的代码?当然,程序始终是一个翻译单元吗?2)如果客户端代码包含FileSystem.h,行
extern FileSystem tfs;
是否足以让客户端代码调用tfs(我很欣赏初始化可能存在运行时问题,我只是在谈论编译时范围)?编辑到Q1
该书说这两段代码在单独的翻译单元中。知道客户端代码在单独的翻译单元中,客户端代码如何使用变量
tfs
? 最佳答案
这是一个简化示例,说明如何跨多个TU进行初始化会出现问题。
gadget.h:
struct Foo;
extern Foo gadget;
gadget.cpp:
#include <foo.h>
#include <gadget.h>
Foo gadget(true, Blue, 'x'); // initialized here
client.cpp:
#include <foo.h>
#include <gadget.h>
int do_something()
{
int x = gadget.frumple(); // problem!
return bar(x * 2);
}
问题在于,不能保证在
gadget
引用该对象之前,该do_something()
对象已被初始化。仅保证一个TU中的初始化程序在调用该TU中的功能之前完成。(解决方案是将
extern Foo gadget;
替换为Foo & gadget();
,在gadget.cpp中将其实现为{ static Foo impl; return impl; }
并使用gadget().frumple()
。)