当我作为软件开发人员的第一份工作开始时,我被指派创建一个系统,允许从PDF文档中写入和读取C ++值(或对象)。这需要一个用于将类型映射到id的系统,反之亦然。代码库非常庞大,并且有几个“层”代码(基本框架层,工具层,视图层等)。建议的解决方案是向每个图层添加一个头文件,其枚举包含特定图层中定义的类型的ID。为避免冲突,每个枚举的第一个值都以偏移值(1000,2000,3000,...)开头。
由于这个系统对我来说似乎有些笨拙,所以我决定尝试别的东西,并提出了代表独特ID的课程:
// UniqueId.h
class UniqueId
{
public:
UniqueId();
operator int() const;
private:
int mId;
static int sCounter;
};
// UniqueId.cpp
int UniqueId::sCounter = 0;
UniqueId::UniqueId()
{
mId = ++sCounter;
}
UniqueId::operator int() const
{
return mId;
}
现在只需创建一个UniqueId对象列表而不用担心冲突的ID,而不是枚举。
审核我的代码的人(公司的软件架构师)首先同意这一点。但是,一天后他改变主意,告诉我这个系统不起作用。我依稀记得他提到多个编译单元会出现问题。
今天,大约四年后,我仍然不明白问题本来是什么。据我所知,静态变量只能在一个编译单元(UniqeId.cpp)中定义。
所以..由于StackOverflow是如此丰富的资深开发人员,我想借此机会要求澄清一下。这确实是一个问题吗?或者我的想法好吗?
答案 0 :(得分:4)
他可能指的是Static Initialization Order Fiasco。
我发现你发布的内容没有问题。您需要依赖其他翻译单元中的静态变量来解决惨败问题。
答案 1 :(得分:4)
在程序的不同运行之间为“类型”分配相同的ID是否重要?如果没有,一切都应该没问题。如果是的话......
不同的“类型”如何抓取他们的ID?一种方法可能是:
class FooType
{
private:
static UniqueId myId;
...
};
这会调用Fred Larson链接到的static initialization order fiasco。由于静态的初始化顺序未定义,因此从构建到构建可能会获得分配给myId的不同值,或者如果您真的不幸,则从运行到运行。
您可以仅在需要时创建UniqueId
的实例,例如在对象的构造函数中或作为具有静态变量的方法。例如:
class BarType
{
private:
const UniqueId &getMyId()
{
static UniqueId myId;
return myId;
}
....
};
现在您可能不得不担心线程安全(如果您正在开发多线程程序)。除此之外,UniqueId
值在很大程度上取决于程序的流程,并且很可能在运行之间发生变化。在程序的一次运行中,您可能永远不需要实例化BarType
,因此它不会声明ID。在另一场比赛中,您可能需要提前BarType
;在另一个你可能需要BarType
之后。
更加险恶的是,一切都可能适用于许多版本,直到你忘记了所有这些设置。有人添加了一个新的“类型”,一些现有的类型,或者很可能做出一个完全不相关的变化。然后突然之间所有因为上面列出的原因之一而中断。
答案 2 :(得分:1)
您的代码对我来说似乎很好,并且明确地比系统的所有“层”中具有保留值的枚举更好。即使以这种方式使用静力学存在问题,也会有解决方案,例如GUID。你的想法确实很好。请记住,软件架构师只是一个提高工资的开发人员的名字 - 这并不意味着他比你更熟练;)