简体   繁体   English

构造函数排序(全局范围)问题

[英]Constructor ordering (global scope) issue

I have a constructor ordering issue that I am trying to come up with creative ways to solve. 我遇到一个构造函数排序问题,我试图用创造性的方法来解决。

Basically I have a simple class Color which stores RGB colour information and allows manipulation of said colour and conversion into other colour spaces (24 bit, 16 bit, 4 bit, HSV, XYZ, LAB, etc). 基本上,我有一个简单的Color类,它存储RGB颜色信息,并允许操纵该颜色并将其转换为其他颜色空间(24位,16位,4位,HSV,XYZ,LAB等)。 The class itself is working perfectly. 该类本身运行良好。

I also have a library of pre-defined colours, such as: 我也有一个预定义的颜色库,例如:

namespace Colors {
    const Color Snow                  (255,250,250);
    const Color GhostWhite            (248,248,255);
    const Color WhiteSmoke            (245,245,245);
    const Color Gainsboro             (220,220,220);
    const Color FloralWhite           (255,250,240);
    const Color OldLace               (253,245,230);
    const Color Linen                 (250,240,230);
    const Color AntiqueWhite          (250,235,215);
    const Color PapayaWhip            (255,239,213);
    const Color BlanchedAlmond        (255,235,205);
};

And they all work fine too when used in a program normally. 当它们在程序中正常使用时,它们也都可以正常工作。

My issue comes when I try to use those library colours in the constructor to another object. 当我尝试在构造函数中将这些库颜色用于另一个对象时,就会出现我的问题。 There is nothing to say that the constructor for the library colour I use has been executed and the colour data assigned (it does some small pre-processing to calculate some of the different colour space values) before the constructor for the other class that receives the Color object and assigns it to a storage variable inside itself. 没什么可说的是,我使用的库颜色的构造函数已经执行,并且在接收到其他颜色的其他类的构造函数之前分配了颜色数据(它进行了一些小的预处理以计算一些不同的颜色空间值)。 Color对象,并将其分配给自身内部的存储变量。

For example, the Color class has a constructor: 例如,Color类具有一个构造函数:

Color(const Color &c) {
    setColor(c.getRed(), c.getGreen(), c.getBlue());
}

And an = operator: =运算符:

Color &Color::operator=(const Color &rhs) {
    setColor(rhs.getRed(), rhs.getGreen(), rhs.getBlue());
    return *this;
}

setColor() is just a little helper function that stores the values and pre-calculates some colour space alternative values. setColor()只是一个辅助函数,用于存储值并预先计算一些颜色空间替代值。

When I include one in the constructor of another object, say: 当我在另一个对象的构造函数中包含一个时,说:

Color _storeColor;
TestClass(const Color &c) {
    _storeColor = c;
}

or: 要么:

Color _storeColor;
TestClass(const Color &c) : _storeColor(c) {}

with: 与:

TestClass myTest(Colors::WhiteSmoke);

the colour data assigned is (nearly always) all 0 as if the constructor for the Color class hasn't been run yet, which I totally get. 分配的颜色数据(几乎总是)全为0 ,就好像尚未运行Color类的构造函数一样,我完全明白了。

So I am looking for ideas on how I can create my library of pre-defined colours in such a way that they will be available to other constructors in the global scope. 因此,我正在寻找有关如何创建预定义颜色库的想法,以使它们可用于全局范围内的其他构造函数。

Incidentally, things like: 顺便说一句,像:

TestClass myTest(Color(245,245,245));

work perfectly, though I'd prefer not to have hundreds (and it is hundreds) or #define macros for the colour library since that would cause lots of unnecessary object duplication and I'd prefer to keep it as always referencing the same global instances whenever a colour is re-used. 可以完美地工作,尽管我不希望颜色库有数百个(它是数百个)或#define宏,因为这会导致大量不必要的对象重复,并且我希望将其始终引用同一全局实例每当重新使用颜色时。

The C++ standard does not define the order in which constructors in different translation units get called, as you are aware. 如您所知,C ++标准未定义调用不同翻译单元中的构造函数的顺序。

But most C++ implementations typically provide means of specifying the constructor initialization order, which you might be able to use to your advantage. 但是大多数C ++实现通常提供指定构造函数初始化顺序的方法,您可能可以利用这些顺序来获得好处。

For example, gcc has the init_priority attribute that you can attach to a constructor and control the constructor's initialization order with respect to other constructors. 例如,gcc具有init_priority属性,您可以将其附加到构造函数,并控制该构造函数相对于其他构造函数的初始化顺序。 This would likely be the answer in gcc's case. 在gcc的情况下,这可能就是答案。

Check your compiler's documentation for more information on what compiler-specific features it offers in this area. 请查看编译器的文档,以获取有关此区域提供哪些特定于编译器的功能的更多信息。

For a more portable approach, it might be possible to do something with the fact that PODs get initialized before non-trivial class instances, at namespace scope. 对于更可移植的方法,可能会做一些事情,即在命名空间范围内,在非平凡的类实例之前初始化POD。 It might be possible to leverage this, in order to come up with some approach here, but I'll suggest investigating your compiler's abilities, first. 为了在这里提出一些方法,可能可以利用它,但是我建议您首先研究一下编译器的功能。 There's nothing wrong with taking advantage of additional features that your compiler offers you. 利用编译器为您提供的其他功能没有错。

What you encountered is sometimes called "static initialization order fiasco". 您遇到的内容有时称为“静态初始化顺序失败”。

One of the ways of dealing with it would be using Construct On First Use Idiom , implemented eg by changing your colours definitions to getter functions: 处理它的一种方法是使用“首次使用惯用语构造” ,例如通过将颜色定义更改为吸气剂函数来实现:

const Color & Snow(void) {
    static Color snow(255,250,250);
    return snow;
}

You can read more in this article . 您可以在本文中阅读更多内容


Edit: to avoid excessive amounts of code, you can simply define a helper macro: 编辑:为避免过多的代码,您可以简单地定义一个辅助宏:

#define DEF_COLOR(name, r, g, b) \
const Color & name(void) { \
    static Color name(r,g,b); \
    return name; \
}

DEF_COLOR(Snow,       255,250,250)
DEF_COLOR(GhostWhite, 248,248,255)
// ...

If you can use C++11 , you may also try to arrange your preprocessing such that it can be computed at compile time and make the color definitions a constexpr : 如果可以使用C++11 ,则还可以尝试安排预处理,以便可以在编译时对其进行计算,并使颜色定义成为constexpr

class Color {
    public:
        int m_r, m_g, m_b;
        constexpr Color(int r, int g, int b) : m_r(r), m_g(g), m_b(b) {}
        constexpr Color(Color const& o) : m_r(o.m_r), m_g(o.m_g), m_b(o.m_b) {}
};

constexpr const Color RED = Color(255,0,0);
constexpr const Color BLUE = Color(0,255,0);
constexpr const Color GREEN = Color(0,0,255);

This should guarrante that the colors are initialized before other constructors are called (constant initialization takes place before dynamic initialization) . 这应该保证颜色在调用其他构造函数之前已初始化(恒定初始化发生在动态初始化之前)。 It has the additional benefit that the compile may perform your preprocessing at compile time, so it might even be a little more efficient (however, this also means it won't work if your preprocessing depends on values only available during run-time). 它还有一个额外的好处,就是编译可以在编译时执行预处理,因此效率可能更高(但是,这也意味着如果预处理仅依赖于运行时可用的值,它将无法工作)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM