C++链接错误:静态变量的初始化问题

在使用C++时,编译项目时偶尔会发生链接,这些错误很多时候是偶发的,可能再编一次,或者换个模式,换个参数,就没有编译错误了,但之后可能还会出现。由于是在编译阶段,问题不容易排查。这样的错误有可能就是静态变量的初始化问题。

  • 简单概括:当静态变量的初始化过程中,需要其他静态变量的值时,就有可能产生不确定的链接错误。
  • 主要原因:C++不固定静态变量的初始化顺序,在初始化静态变量时,如果你需要其他静态变量的值,但这个值又没有初始化,问题就发生了。
  • 解决方案:
    1. 尽量不要在静态初始化时引入其他静态变量,尤其避免循环依赖。
    2. 将静态变量,放到函数里面去,即:
    A& variable_name(){
      static A variable = ...;
      return variable;
    }
    
    每次想访问这个静态变量时,改为用variable_name()来进行访问,这个函数也没必要是成员函数,跟这个类一起放到头文件里就可以了(内联inline)。在函数内的局部静态变量第一次访问是初始化,之后自动再调用函数自动略过初始化语句。
    1. 为C++入口的_init()函数提供自定义实现,这个函数负责初始化静态变量,在这个函数内部人工确定顺序。(一般非必要不使用)

好的,接下来我们深入剖析下这个问题:

  • C语言没有这样的链接错误:C语言可以很简单的处理初始化变量,无论是基本类型还是结构体,在编译阶段就可以将初始化值放入.data节,自然就不存在这样的问题。C++的对象是由构造函数来构建的,编译时不执行代码,因此无法确定具体值,只能放在运行时完成。
  • 静态变量的初始化如果不牵涉其他任何自定义类型则不会出现问题:因为不会出现顺序问题,所以可以按正常语法初始化。
  • 那些需要其他静态变量的值做初始化的静态变量,最好按照方案2重写避免链接问题。

顺便说一句,对于非静态变量,比如类中的成员变量,在构造函数中,尽量以初始化列表的方式初始化,即

A(int _a, double _b, B & _c)
: a(_a),b(_b),c(_c),d()
{}

如果在函数体内执行,实际上是用默认构造函数初始化了一次,又赋值了一次。
而且,如果是常量对象和引用对象,则必须如此初始化!!

  • 还有一个值得注意的点:类内成员的初始化顺序,是按照他们在头文件中的排列顺序决定的,和构造函数的初始化列表无关。

参考资料:

  • 《Effective C++》第三版,条款04
  • 《高级C/C++编译技术》:第6章

你可能感兴趣的:(C++链接错误:静态变量的初始化问题)