问题产生:
在代码中的某个头文件定了几个全局的 const std::string ,同时定义了某个类,在类的构造函数中使用了这几个全局变量。
该类作为单例模板的成员被使用了,单例的编译在另外一个单元。
程序编译链接正常,运行时候segment fault
gdb调试const 成员变量,内存不可访问
分析该问题需要具备的基础知识:
知识一:
全局变量、文件域的静态变量和类的静态成员变量在main执行之前的静态初始化过程中分配内存并初始化;
局部静态变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象。
知识二:
对于出现在同一个编译单元内的全局变量来说,它们初始化的顺序与他们声明的顺序是一致的(销毁的顺序则反过来),而对于不同编译单元间的全局变量,c++ 标准并没有明确规定它们之间的初始化(销毁)顺序应该怎样,因此实现上完全由编译器自己决定,一个比较普遍的认识是:不同编译单元间的全局变量的初始化顺序是不固定的,哪怕对同一个编译器,同一份代码来说,任意两次编译的结果都有可能不一样。
问题解决:
方案一:
使用宏替换了const变量
方案二:
由于这几个常量只在定义的类中用到,放在了类成员里。
对于该问题,可以参考google C++编码规范的描述:
class
类型的全局变量是被禁止的,内建类型的全局变量是允许的,当然多线程代码中非常数全局变量也是被禁止的。永远不要使用函数返回值初始化全局变量。
不幸的是,全局变量的构造函数、析构函数以及初始化操作的调用顺序只是被部分规定,每 次生成有可能会有变化,从而导致难以发现的 bugs
。
因此,
禁止使用 class 类型的全局变量(包括 STL 的 string, vector 等等)
,因为它们的初始化顺序有可能导致构造出现问题。
内建类型和由内建类型构成的没有构造函数的结构体可以使用,如果你一定要使用
class
类型的全局变量,请使用
单件模式(
singleton pattern)
。
对于全局的字符串常量,使用
C
风格的字符串,而不要使用
STL
的字符串:
const char kFrogSays[] = "ribbet";
虽然允许在全局作用域中使用全局变量,使用时务必三思。大多数全局变量应该是类的静态 数据成员,或者当其只在.cc
文件中使用时,将其定义到不具名命名空间中,或者使用静态
关联以限制变量的作用域。 记住,静态成员变量视作全局变量,所以,也不能是 class
类型!