我遇到以下问题:
我有一个Color类,为了这个问题的目的,减少到:
// Color.h
struct Color {
int r,g,b;
Color() : r(0), g(0), b(0) {}
Color(int r_, int g_, int b_) : r(r_), g(g_), b(b_) {}
static const Color Red;
static const Color Magenta;
};
// Color.cpp
#include "Color.h"
const Color Color::Red (255,0,0);
const Color Color::Magenta (255,0,255);
即,我想使用类名作为某些预定义颜色的范围。
现在,我在全球范围内的用户文件中执行以下操作:
//user.cpp
#include "Color.h"
static const Color colors[2] = { Color::Red, Color::Magenta };
当我使用颜色[i]时,我发现它们充满了0。 我查了一下,看到第一次调用空构造函数(由于很快就会显示出来的原因没有意义),然后我将空的c'tor更改为:
Color() : r(200), g(200), b(200) {}
得到了相同的结果。
我尝试将颜色定义为constexpr,如下所示:
static constexpr Color Red (255, 0, 0);
但它说: 数字常量之前的预期标识符
然后像这样:
static constexpr Color Red = {255, 0, 0};
就像这样:
static constexpr Color Red = Color(255, 0, 0);
然后编译失败,因为“'Color'未在此范围内声明”,“Red有不完整的类型”(真的吗?) 所以现在使用空c'tor真的没有意义,而是整个内存用0初始化。
在运行时我可以使用静态const颜色,它可以工作。
我的这种行为甚至定义明确?它取决于编译/链接顺序吗?
我该如何解决?
由于
答案 0 :(得分:3)
您正在遇到Static Initialization Order Fiasco。听起来colors
数组在Red
和Magenta
对象之前被初始化了。
一个解决方案是Construct On First Use Idiom:
// Color.h
struct Color {
int r,g,b;
Color() : r(0), g(0), b(0) {}
Color(int r_, int g_, int b_) : r(r_), g(g_), b(b_) {}
static const Color& Red();
static const Color& Magenta();
};
// Color.cpp
#include "Color.h"
const Color& Color::Red()
{ static const Color red(255,0,0); return red; }
const Color& Color::Magenta()
{ static const Color magenta(255,0,255); return magenta; }
//user.cpp
#include "Color.h"
static const Color colors[2] = { Color::Red(), Color::Magenta() };