简体   繁体   English

在构造函数中初始化的变量未保持初始化状态(C ++)

[英]Variables initialized in constructor not staying initialized (c++)

I've been working in C++ for awhile now, but I've never encountered this error before. 我已经在C ++中工作了一段时间,但之前从未遇到过此错误。 I have a struct (named skew_value) that has an initialization method so that everything can have proper default values (if it has more than a constructor and destructor, I make it a class instead of a struct). 我有一个具有初始化方法的结构(名为skew_value),以便所有内容都可以具有适当的默认值(如果它具有多个构造函数和析构函数,则将其设为类而不是结构)。 I've verified that the constructor is indeed being called (break points). 我已验证确实调用了构造函数(断点)。 And the variables are being properly set. 并且已正确设置了变量。 But once the constructor is finished, everything is uninitialized. 但是,一旦构造函数完成,一切都不会初始化。

The code is as follows: 代码如下:

#ifndef _LBMOON_GRAPHICSYSTEM_SKEW_VALUE_H
#define _LBMOON_GRAPHICSYSTEM_SKEW_VALUE_H

struct skew_value
{
    skew_value(float tlX=1, float tlY=0, float trX=0, float trY=0, float blX=0, float blY=0, float brX=0, float brY=0)
    {
        skew_value(Vector2f(tlX,tlY), Vector2f(trX,trY), Vector2f(blX,blY), Vector2f(brX,brY));
    }

    skew_value(Vector2f topLeft, Vector2f topRight, Vector2f bottomLeft, Vector2f bottomRight)
    {
        TLSkew = topLeft;
        TRSkew = topRight;
        BLSkew = bottomLeft;
        BRSkew = bottomRight;

        xScale = 1;
        yScale = 1;
    }

    float xScale;
    float yScale;

    Vector2f TLSkew;
    Vector2f TRSkew;
    Vector2f BLSkew;
    Vector2f BRSkew;

    Vector2f TLOrigin;
    Vector2f TROrigin;
    Vector2f BLOrigin;
    Vector2f BROrigin;

    unsigned int TLIndex;
    unsigned int TRIndex;
    unsigned int BLIndex;
    unsigned int BRIndex;
};



#endif

Vector2f is a class containing two float variables. Vector2f是一个包含两个float变量的类。 Scale is normally one of these, but I switched it to two float variables to test that the problem didn't lie in the Vector2f class. Scale通常是其中之一,但是我将其切换为两个float变量以测试问题是否出在Vector2f类中。

Any explanation you can give as to why the constructor is being called, but then all the variables being de-initialized would be great. 您可以对为何调用构造函数的原因给出任何解释,但是随后所有被取消初始化的变量都会很棒。 It happens whether I make the class a pointer or not. 无论是否使类成为指针,都会发生。 It also doesn't matter which constructor I call or if I provide arguments. 调用哪个构造函数或是否提供参数也无关紧要。 It just refuses to keep track of the data after the constructor has been called. 在构造函数被调用后,它只是拒绝跟踪数据。

The problem is that you aren't returning the object you are initializing with those values. 问题在于您不返回使用这些值初始化的对象。 Your call to skew_value constructor taking float arguments constructs and initializes a temporary anonymous automatic skew_value object but doesn't copy it into the object you are supposed to be constructing nor does it modify it. 您对skew_value float参数的skew_value构造函数的调用将构造并初始化一个临时的匿名自动skew_value对象,但不会将其复制到您应该构造的对象中,也不会对其进行修改。 As such the changes aren't reflected in the object ultimately returned. 因此,更改不会反映在最终返回的对象中。

C++ isn't Java or C# where you can call nested constructors natively this way (from the body of a function). C ++不是Java或C#,您可以在本地以这种方式(从函数主体)调用嵌套构造函数。

However... 然而...

C++11 introduced this ability; C ++ 11引入了此功能; you just aren't using the proper syntax for it. 您只是没有使用正确的语法。 It should be called like an initializer list argument. 应该像初始化列表参数一样调用它。

You should instead say: 您应该说:

struct skew_value
{
    skew_value( float tlX=1, float tlY=0, float trX=0,
                float trY=0, float blX=0, float blY=0,
                float brX=0, float brY=0)
    : skew_value( Vector2f( tlX, tlY ), 
                  Vector2f( trX, trY ), 
                  Vector2f( blX, blY ), 
                  Vector2f( brX, brY ) )
    {
    }

    skew_value(Vector2f topLeft, Vector2f topRight, 
               Vector2f bottomLeft, Vector2f bottomRight)
    {
        TLSkew = topLeft;
        TRSkew = topRight;
        BLSkew = bottomLeft;
        BRSkew = bottomRight;

        xScale = 1;
        yScale = 1;
    }
    ....
}

IF C++11 features can't be used IF C ++ 11功能无法使用
Then you will have to do it the long way and again it's suggested to use an initializer list to initialize all of your values. 然后,您将不得不做很长的路要走,建议再次使用初始化列表来初始化所有值。

Additional Reference 附加参考
Find more in this related question which might this might be a duplicate of: Can I call a constructor from another constructor (do constructor chaining) in C++? 在此相关问题中找到更多内容,可能与以下内容重复: 我可以在C ++中从另一个构造函数调用构造函数(进行构造函数链接)吗?

In this code, 在这段代码中

skew_value(float tlX=1, float tlY=0, float trX=0, float trY=0, float blX=0, float blY=0, float brX=0, float brY=0)
{
    skew_value(Vector2f(tlX,tlY), Vector2f(trX,trY), Vector2f(blX,blY), Vector2f(brX,brY));
}

the constructor call in the middle is creating a temporary and initializing that. 中间的构造函数调用创建一个临时并将其初始化。

C++11 does support constructor forwarding, but it has a different syntax, I've never used it, and your compiler may not necessarily support it. C ++ 11确实支持构造函数转发,但是它具有不同的语法,我从未使用过它,并且您的编译器可能不一定支持它。

Instead, I suggest you use either a base class constructor, or an object factory function. 相反,我建议您使用基类构造函数或对象工厂函数。 I would not use an init method, because there are strong reasons not to (some discussed by Bjarne in his exception safety appendix to 3rd edition of "The C++ Programming Language"). 我不会使用init方法,因为有很多理由不这样做(Bjarne在他的“ C ++编程语言”第三版的异常安全附录中对此进行了讨论)。 But in the end that may be what you will end up doing, and it's not that dangerous until you start requiring client code to call it. 但是最终,这可能是您最终要做的事情,并且在您开始要求客户端代码调用它之前,并不是那么危险。


Note that you're leaving the member variables TLIndex , TRIndex , BLIndex and BRIndex uninitialized . 请注意,您将未初始化成员变量TLIndexTRIndexBLIndexBRIndex That means that they will have indeterminate values . 那意味着他们将有不确定的价值 With some compilers and options those values will be 0, but with others they will be more obviously arbitrary, and that can easily be a source of bugs. 对于某些编译器和选项,这些值将为0,而对于其他编译器和选项,则这些值将更加明显是任意的,并且很容易成为错误的来源。


Also note that the preprocessor symbol 另请注意,预处理器符号

_LBMOON_GRAPHICSYSTEM_SKEW_VALUE_H

is invalid. 是无效的。 All names staring with underscore followed by uppercase letter are reserved to the implementation. 所有带有下划线后跟大写字母的名称都保留给实现。 And so are names containing two subsequent underscores. 包含两个下划线的名称也是如此。

In this case I doubt that you'd get any inadvertent text substitution or redefinition effect, but a really perverse compiler could treat this as an error, and anyway it's a bad habit that's best corrected. 在这种情况下,我怀疑您是否会因疏忽而导致文本替换或重新定义效果,但是真正错误的编译器会将其视为错误,并且无论如何,这是一个最好的纠正习惯。 ;-) ;-)


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

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