构造函数中未定义的全局常量
Global constants undefined in constructor
我有两个常量文件:
// 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)
class和常量定义在同一个命名空间中,不会给我一个常量未定义的错误。对象初始化后(例如使用硬编码字符串),它可以正常工作并打印出常量值 ("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:
这种情况下的解决方案是在头文件中定义一个静态内联函数,如 and 所建议的那样。他们都对最终答案做出了贡献。
代码如下:
inline std::string getTestString() { return "defined!"; }
这允许将非 constexpr
类型作为全局常量。
在中,constants.cpp
翻译单元,testString
将在任何后续定义的非局部变量之前被初始化。 在个翻译单元之间,我们有所谓的"static initialization order fiasco"; constants.cpp
以外的任何翻译单元都不能假设 testString
已经初始化,直到 main
开始执行,所以如果它试图在它自己的非本地初始化之一期间读取它的值,那么它可能会观察到一个零初始化的 std::string
对象,该对象具有未定义的行为。
我的建议是避免这个问题,这也是我以前工作场所遵循的规则,如果你必须有全局常量,尽可能使它们 constexpr
,并且要非常小心任何非-constexpr
全局变量。 std::string
还不是 constexpr
,但老式的 char
数组可以工作:
// constants.h
inline constexpr char testString[] = "defined!";
// constants.cpp
// no need to define `testString` here!
我有两个常量文件:
// 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)
class和常量定义在同一个命名空间中,不会给我一个常量未定义的错误。对象初始化后(例如使用硬编码字符串),它可以正常工作并打印出常量值 ("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:
这种情况下的解决方案是在头文件中定义一个静态内联函数,如
代码如下:
inline std::string getTestString() { return "defined!"; }
这允许将非 constexpr
类型作为全局常量。
在中,constants.cpp
翻译单元,testString
将在任何后续定义的非局部变量之前被初始化。 在个翻译单元之间,我们有所谓的"static initialization order fiasco"; constants.cpp
以外的任何翻译单元都不能假设 testString
已经初始化,直到 main
开始执行,所以如果它试图在它自己的非本地初始化之一期间读取它的值,那么它可能会观察到一个零初始化的 std::string
对象,该对象具有未定义的行为。
我的建议是避免这个问题,这也是我以前工作场所遵循的规则,如果你必须有全局常量,尽可能使它们 constexpr
,并且要非常小心任何非-constexpr
全局变量。 std::string
还不是 constexpr
,但老式的 char
数组可以工作:
// constants.h
inline constexpr char testString[] = "defined!";
// constants.cpp
// no need to define `testString` here!