0

I've been working in C++ for awhile now, but I've never encountered this error before. 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). 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. 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.

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.

Legacyblade
  • 335
  • 1
  • 5
  • 18
  • 1
    When using your debugger, look for the value of this in the different constructor calls. ;-) http://ideone.com/tNMi37 – Hiura Apr 07 '14 at 15:39
  • You should add emphasis to the word `this` in that statement :-) good hint of course – UpAndAdam Apr 07 '14 at 15:45

2 Answers2

7

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. 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).

However...

C++11 introduced this ability; 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
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++?

Community
  • 1
  • 1
UpAndAdam
  • 4,515
  • 3
  • 28
  • 46
  • Thank you so much ^.^ I understand exactly how that all works now. Now I have to go fix a few other of my structs that I haven't gotten around to testing that I made the same mistake in, lol. I really appreciate your help! – Legacyblade Apr 07 '14 at 15:49
0

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.

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"). 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. 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.


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. ;-)


Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331