【问题标题】:private variables are read later than member init list?私有变量的读取时间晚于成员初始化列表?
【发布时间】:2016-09-06 17:02:42
【问题描述】:

我有这门课:

class IPianoRoll : public IControl
{
private:
    int x, y;
    int w = 30 * numStep + 1;
    int h = 8 * numSemitones + 1;
    int o = 5;

public:
    IPianoRoll(IPlugBase* pPlug, int pX, int pY) : IControl(pPlug, IRECT(pX, pY, pX + o + w + o, pY + o + h + o)) {
        x = pX;
        y = pY;
    }
}

但似乎私有变量值比成员初始化列表“晚”可用。所以owh 不是用我的值初始化的,它采用不同的值。

有没有办法预先初始化私有变量?

【问题讨论】:

    标签: c++ initialization private


    【解决方案1】:

    首先构造基类(如果有多个基类,从左到右),然后按照声明的顺序构造成员变量(不是在任何成员初始化列表中的顺序)。

    但这仅适用于非静态成员变量。从您的示例来看,who 是适用于类的所有实例的常量。因此,您只需将类更改为:

    class IPianoRoll : public IControl
    {
    private:
        int x, y;
        static const int w = 30 * numStep + 1;
        static const int h = 8 * numSemitones + 1;
        static const int o = 5;
    
    public:
        IPianoRoll(IPlugBase* pPlug, int pX, int pY) 
           : IControl(pPlug, IRECT(pX, pY, pX + o + w + o, pY + o + h + o)) 
           , x(pX)
           , y(pY)
        {
        }
    };
    

    一切都会好起来的。请注意,我已将设置 x 和 y 移到成员初始化列表中。

    如果您希望变量是非静态的(以便以后可以针对类的不同实例更改它们),那么我会写如下内容:

    class IPianoRoll : public IControl
    {
    private:
        int x, y;
        static const int w_default = 30 * numStep + 1;
        static const int h_default = 8 * numSemitones + 1;
        static const int o_default = 5;
    
        int w = w_default;
        int h = h_default;
        int o = o_default;
    
    public:
        IPianoRoll(IPlugBase* pPlug, int pX, int pY) 
           : IControl(pPlug, IRECT(pX, pY, pX + o_default + w_default + o_default, 
                                           pY + o_default + h_default + o_default)) 
           , x(pX)
           , y(pY)
        {
        }
    };
    

    【讨论】:

    • 不错。那么静态变量值是在任何基类/成员变量之前“存储”的吗?
    • 我仍然认为这是 UB。 IControl 基类将在子类中的 statics 之前初始化,并且您将未初始化的 statics 传递给 iControl 构造函数!编译器很可能会吃掉你的猫。不过,我很想被证明是错误的。
    • 是的。实际规则比较复杂,但基本上它们的值是在程序启动时设置的(常量整数值可以用作编译时常量。)
    • @Bathsheba:错误,不。静态变量的初始化不迟于翻译单元中定义的第一个函数的入口 - 因此它们必须在构造函数启动之前初始化。在这种情况下,这并不意味着“在构造函数的主体之前”(空的 {}),它意味着在构造函数的任何部分之前。你需要标准中的章节吗?
    • 我可能会这样做 ;-) 如果 IControl 与 IPianoRoll 位于不同的翻译单元中怎么办?您确实同意IControl 是完全构造的 IPianoRoll 中的任何内容被构造?
    【解决方案2】:

    类成员的访问说明符不相关。 相关的是它们在类声明 中出现的顺序。类成员按 顺序初始化。

    依赖于类成员的特定初始化顺序是非常危险的,因为错误的重构器可能会在头文件中重新排序它们,而完全不知道源文件依赖于特定的顺序。

    您还应该注意,读取未初始化变量的行为是未定义的。

    【讨论】:

    • 这里的顺序没有任何意义。我的意思是:这些值不是在 CTOR 中采用的,所以我只是将不是 5 作为o 传递,因为它不是 init。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 2016-07-22
    • 2015-11-28
    • 1970-01-01
    • 2016-02-07
    • 2019-10-23
    相关资源
    最近更新 更多