2

Can someone help me to understand why the following code causes a warning

struct A
{
  A() : _a( 0 ) {}

  const int& _a;
};


int main()
{
  A a;
}

with warning

warning: binding reference member '_a' to a temporary value [-Wdangling-field]
      A() : _a( 0 ) {}

but this code, where std::move is used to initialize the member _a, does not:

struct A
{
  A() : _a( std::move(0) ) {}

  const int& _a;
};


int main()
{
  A a;
}

Aren't 0 and std::move( 0 ) both r-values?

abraham_hilbert
  • 2,221
  • 1
  • 13
  • 30
  • Where does _a refer here ? – Steephen Nov 18 '16 at 13:25
  • 9
    `_a` is a reference, in ex1 you bind it to a temporary (`0`), using it later is UB. In ex2 you use `std::move` as a cast to "lie" to the compiler, it silences the warning but accessing it later is still UB. – Richard Critten Nov 18 '16 at 13:27
  • `const &` does not extend the lifetime when used in a class. It only works for function parameters and function returns. – NathanOliver Nov 18 '16 at 13:29
  • @NathanOliver I think you're mixing it up with something else. `foo(bar{});` won't change the lifetime of the `bar` from spanning the full-expression, on the other hand `bar const &b = bar{};` does extend the `bar`'s lifetime without a function in sight. – Quentin Nov 18 '16 at 13:33
  • 1
    @Quentin Yeah there is a couple other cases. My main point was that you cannot pass a temporary to a class by `const &` and have the class extend the lifetime. – NathanOliver Nov 18 '16 at 13:40
  • @NathanOliver indeed. – Quentin Nov 18 '16 at 13:44

2 Answers2

9

This is an expression:

0

It's a very small expression, true. But it is an expression.

Once the expression is evaluated, it goes away. It disappears. Joins the choir invisible. Goes to meet its maker. It becomes an ex-expression.

It is true that binding a const reference to a temporary extends the scope of the temporary value until the end of the enclosing scope.

But in this case, the scope of the expression is the constructor. When the constructor is done, the temporary value gets destroyed.

Your compiler noticed the fact that a const reference to the expression still continues to exist, though, as a class member. Your compiler is advising you that using the class member will now result in undefined behavior. Your compiler wants to be your friend. Your compiler doesn't want you to write buggy code, so you're getting some free, friendly advice, from your compiler.

In the other case, you have added some additional code which is slightly more complicated. It is still undefined behavior, but the code is now complex enough that the compiler cannot see that undefined behavior results. But it's still the same bug.

A compiler will try to warn you of potential problems, when the compiler sees them. Unfortunately, the compiler cannot find all possible potential problems, every time. But, when it's obvious, the compiler will let you know.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
-1

Their return values are not exactly the same. From cppreference.com

In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.

Now, looking at rvalue references, we see that object "0" in second example can live longer:

An rvalue may be used to initialize an rvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.

Such reference (rvalue reference) is afterwards assigned to the class member _a, which is allowed, so you are having no error.

Moreover, rvalue reference to a temporary can be used in a move constructor, so if the member you are initialising has it, I don't see the problem. However, in C++ you can never know when undefined behaviour can suddenly hit you :)

Noidea
  • 1,405
  • 11
  • 17
  • Cppreference explains this where it explains lifetime extension. Now linked from the sentence you quoted. – Cubbi Nov 18 '16 at 14:58
  • @Cubby, sorry, what is linked now? Shall I link something? – Noidea Nov 18 '16 at 15:02
  • The word "extended" in that sentence on cppreference is now clickable, and leads to the page that explains the problem. – Cubbi Nov 18 '16 at 15:37