问题
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?
回答1:
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.
回答2:
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 :)
来源:https://stackoverflow.com/questions/40678256/r-value-causes-a-warning-without-the-use-of-stdmove