阅读382 返回首页    go 阿里云 go 技术社区[云栖]


C++编程规范之21:避免跨编译单元的初始化依赖

摘要:

    保持顺序,不同编译单元中的名字空间级对象决不应该在初始化上互相依赖,因为其初始化顺序是未定义的。这样做会惹出很多麻烦,轻则在项目中稍做修改就会引发奇怪的崩溃,重则出现严重的不可移植问题——即使是同一编译器的新版本也不行。

    在不同的编译单元中定义两个名字空间级的对象时,先调用哪一个对象的构造函数是没有定义的。经常工具可能会碰巧按照编译单元目标文件的连接顺序初始化,但这种假设并不总是可靠的;即使确实如此,你总不会希望自己的代码的正确性难以捉摸地依赖于makefile或者项目文件吧。

    因此,在任何名字空间级对象的初始化代码中,不能假设其他编译单元中定义的任何其他对象都已经初始化了。这些考虑方法也适用于动态初始化的原始类型变量。

    请注意,甚至在使用构造函数构造之前,名字空间级对象就已经使用0静态初始化过了。有些自相矛盾的是,这种零初始化会使错误更难以检查,因为静态的零初始化不会迅速使程序崩溃,而是使未初始化对象显现出一种看似合理的表象。你可能认为字符串是空的,指针是空的,整数型变量为0,而事实上,代码已经费劲地将它们初始化了。

    为了避免这一问题,应该尽可能地避免使用名字空间级的变量,它们很危险。如果确实需要可能依赖于另一个变量的此种变量,可以考虑使用singleton设计模式。使用时要小心一些,可以通过确保对象在第一次访问时被初始化,来避免隐含的依赖性。Singleton本质上也是全局变量,它会因为相互依赖或者循环依赖而被破坏。

最后更新:2017-04-03 12:53:43

  上一篇:go J2EE的web.xml中filter-mapping的位置导致的乱码问题
  下一篇:go 连载:面向对象葵花宝典:思想、技巧与实践(2) - 面向对象语言发展历史