Fayeure
Fayeure

Reputation: 1369

How to bind reference to stack allocated class in class constructor?

I have this class

class HumanA
{
    public:

    HumanA(std::string name, Weapon weapon);
    ~HumanA(void);

    inline void     attack(void)
    {
        std::cout << _name << " attacks with his " << _weapon.getType();
    }


    private:

    std::string     _name;
    Weapon          &_weapon;
};

and this constructor

HumanA::HumanA(std::string name, Weapon weapon) : _name(ft::strcapitalize(name)), _weapon(weapon)
{
}

and I get this error at compilation

HumanA.cpp:15:91: error: binding reference member '_weapon' to stack allocated
      parameter 'weapon' [-Werror,-Wdangling-field]
  ...name, Weapon weapon) : _name(ft::strcapitalize(name)), _weapon(weapon)
                                                                    ^~~~~~
./HumanA.hpp:35:12: note: reference member declared here
        Weapon                  &_weapon;
                                 ^
1 error generated.

isn't it possible to have a reference to stack allocated memory? This error seems weird to me.

Upvotes: 3

Views: 1287

Answers (4)

Asteroids With Wings
Asteroids With Wings

Reputation: 17454

isn't it possible to have a reference to stack allocated memory? This error seems weird to me.

It certainly is, but you have to make sure the original object lives at least as long as the reference does. Yours… doesn't. It's a by-value constructor parameter that's effectively local to the constructor, so the reference is left dangling pretty much immediately.

Usually you'd only be getting a warning about this, but your compiler is in -Werror mode, which turns warnings into errors. Good thing too!

If you take a reference into the constructor too, then you'll be binding the reference to the original, original object, which is presumably what you want.

If it's not what you want, if you wanted the class to own a copy of the Weapon, then just forget the reference and std::move the constructor argument into the member (or just copy it again if it's cheap to do so).

Upvotes: 0

zkoza
zkoza

Reputation: 2861

Think:

  1. What is the scope and "time of living" of Weapon weapon object?
  2. What is the answer to the same question for the member Weapon &_weapon?

The answer to the first question is this: weapon exists as long as the constructor is executing. This is a stack-allocated variable that ceases to exist the moment the constructor finishes its job.

The answer to the second question is: member _weapon exists as long as the object that contains this member exists.

So the time of living of weapon is shorter that that of _weapon. Now, what happens when you bind a reference to an object whose time of living is shorter than that of the reference? Well, you'll get a dangling reference. A reference to a memory you don't own. A serious bug that is difficult to spot and difficult to trace unless some special diagnostoc tools have been used, like valgind. In other words, you are free to write this code, but you can access the member only while your program is inside the constructor. This is not something you've intended, isn't it?

Upvotes: 5

Sam Varshavchik
Sam Varshavchik

Reputation: 118340

isn't it possible to have a reference to stack allocated memory

Of course you can. Except that the problem here is that this "stack allocated memory" disappears when the constructor returns, and attempting to use it from that point results in nasal demons and your compiler is smart enough to detect this bug.

Parameters to all functions, including constructors, get destroyed when the function/constructor returns. Capturing a reference to them does not change that.

If you were to declare a reference in the constructor, to its parameter, and use it only in the constructor, nobody will complain about it.

Upvotes: 0

Drew Dormann
Drew Dormann

Reputation: 63775

You are binding a reference to a parameter value. Once the constructor has completed, that parameter is destroyed and the reference is guaranteed to dangle.

Change the parameter to a reference.

HumanA(std::string name, Weapon &weapon);

Upvotes: 0

Related Questions