简体   繁体   中英

Usage of parameter and member variable in constructor

Every so often when writing a constructor of a class, I ask myself whether I should be using the initialized member variable or the constructor parameter. Here are two examples to illustrate what I mean:

Constructor Parameter

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed),
        mEntity(speed)
    { }

private:
    int mSpeed;
    Entity mEntity;
}

Member Variable

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed),
        mEntity(mSpeed)
    { }

private:
    int mSpeed;
    Entity mEntity;
}

Further more the same issue arises with using variables in the constructor body.

Constructor Parameter

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed)
    {
        mMonster.setSpeed(speed);
    }

private:
    int mSpeed;
    Monster mMonster;
}

Member Variable

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed)
    {
        mMonster.setSpeed(mSpeed);
    }

private:
    int mSpeed;
    Monster mMonster;
}

I'm aware that it doesn't really matter (except some special cases), that's why I'm rather asking for comments on code design, than what makes it work and what doesn't.

If you need a specific question to work with: What way yields a nice and consistent code design and does one have an (dis)advantage over the other?

Edit: Don't forget the second part of the question. What about variables in the constructor body?

I would use the Constructor Parameter, because when using that initializer, the order in which those initializers are executed is dictated by the order in which members were declared, not the order in which they are listed. so, be carefull here.

I personally prefer to use the constructor parameter in order to avoid using a not initialized yet member variable.

Indeed, in this example:

class Foo {
private:
    int mEntity;
    int mSpeed;
public:
    Foo(int speed) :
        mSpeed(speed),
        mEntity(mSpeed)
    { }
}

the initialization of mEntity will occur before the initialization of mSpeed (because it is declared before). Therefore you will initialize mEntity with a non initialized mSpeed.

--

And inside the constructor body itself, I would also use the constructor parameter because it is a bit more straightforward while debugging to see that you use speed to initialize mMonster and not mSpeed which is itself initialized with speed . Sure it is a minimalistic overhead, but as we can avoid it easily, I think it is better to do it this way.

I would use the constructor parameter. Why? Because of this question. The construtor parameter is clear and readable, you don't need to know a lot about C++ to know what happens. Using a member is error prone if you don't know enough about C++ and is confusing other people on your team that don't have your level of knowledge, even if you do it right.

If in doubt, keep it simple.

You should definitely use constructor parameters. As mentioned, member variables will be initialized in the order they were declared in the header file and not in the order they appear in the initialization list.

Some compilers will warn you if the orders don't match, but using constructor parameters just gives you one less thing to worry about. It's easy, for example, to introduce bugs this way when you edit your class interface. There is nothing to gain by using member variables to initialize other member variables.

I prefer using the member variable for the case where the parameter must be clamped:

class Foo {
public:
    Foo(int speed) :
        mSpeed((speed < 0 ? 0 : speed)),
        mEntity(mSpeed)
    { }
}

That way if the parameter is invalid it is not used to cause subsequent members to be invalid as well.

Otherwise I stick to the parameter variable.

I would use the constructor parameter, also. See simple example:

// foo.h

class Foo
{
    std::unique_ptr<int[]> mBuff;
    int mSize;
public:
explicit    Foo(int size);
   // other methods...
};

// foo.c
Foo::Foo(int size)
  : mSize(size) 
  , mBuff( std::make_unique<int[]>(size) ) // here using mSize is wrong, 
            // because, mSize is not initialized yet.
            // here mSize initialized after mBuff, because it's declarated after mBuff member.
{}

So if you would use member instead of constructor parameter, you may easy create error situation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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