构造函数中未定义的全局常量

时间:2018-11-14 18:11:24

标签: c++ header-files

我有两个常量文件:

// constants.h
extern const std::string testString;

// constants.cpp
const std::string testString = "defined!";

在程序初始化时,我需要在对象的构造函数中使用此常量,但是它是未定义的。 构造函数中的代码是:

MyClass::MyClass() {
   printf("Value of test string: %s", testString.c_str());
}

// output:
Value of test string: (null)

类和常量在同一个命名空间中定义,并且不会给我一个错误,即常量未定义。初始化对象后(例如,使用硬编码的字符串),它可以正常工作并打印出常量的值(“ defined!”)。原始常量在构造函数中似乎可以正常工作。

我认为这与当时未初始化的常量有关(因此来自.cpp文件)。 你知道为什么会这样吗?在程序完全初始化之后,是否会进行extern const的初始化?

提前谢谢

编辑:

请注意,string类型是为了简化问题,因此将其转换为char并不是一种选择,因为我也对拥有其他非基本类型感兴趣。

显示此问题的程序的最小脏例代码:

// constants.h
extern const std::string testString;

// constants.cpp
#include "constants.h"

const std::string testString = "defined!";

// MyClass.h
class MyClass {

public:
    MyClass();
    virtual ~MyClass();
};

// MyClass.cpp
#include "MyClass.h"
#include "constants.h"

MyClass::MyClass() {
   printf("Value of test string: %s\n", testString.c_str());
}

MyClass::~MyClass() {}

// main.cpp
#include "MyClass.h"
#include "constants.h"

MyClass my;            // undefined string (outputs null)

int main(int argc, char** argv) {
    MyClass my;        // defined string
    return 0;
}

编辑2:

在这种情况下,解决方案是在头文件中定义静态内联函数,如@Brian@LightnessRacesinOrbit所建议。他们俩都为最终答案做出了贡献。

代码如下:

inline std::string getTestString() { return "defined!"; }

这允许具有非constexpr类型作为全局常量。

1 个答案:

答案 0 :(得分:5)

constants.cpp转换单元testString中,constants.cpp将在随后定义的任何非局部变量之前初始化。在翻译单元之间,我们有所谓的“静态初始化顺序惨败”; testString以外的任何转换单元都不能假定main已被初始化,直到std::string开始执行之后,因此,如果它尝试在其自身的非本地初始化中读取其值,那么它可能会观察到一个初始化为零的constexpr对象,该对象具有未定义的行为。

我为避免这个问题的建议(也是我以前的工作场所所遵循的规则)是,如果必须具有全局常数,请尽可能使它们为constexpr,并且对任何非{ {1}}全局变量。 std::string还不是constexpr(但),但是老式的char数组可以工作:

// constants.h
inline constexpr char testString[] = "defined!";

// constants.cpp
// no need to define `testString` here!