2016-11-18 94 views
2

有人可以帮助我理解为什么下面的代码将导致警告R值将导致警告,而不使用std ::的移动

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

    const int& _a; 
}; 


int main() 
{ 
    A a; 
} 

与警告

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

但是这个代码,其中std::move用于初始化成员_a,并不:

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

    const int& _a; 
}; 


int main() 
{ 
    A a; 
} 

是不是0std::move(0)这两个r值?

+0

_a在哪里指这里? – Steephen

+9

'_a'是一个引用,在ex1中你将它绑定到一个临时('0'),以后使用它是UB。在ex2中,你使用'std :: move'作为转换来对编译器进行“撒谎”,它会使警告静音,但稍后访问它仍然是UB。 –

+0

'const&'在类中使用时不延长生命周期。它只适用于函数参数和函数返回。 – NathanOliver

回答

9

这是一个表达式:

0 

这是一个非常小的表情,真的。但这是一种表达。

一旦表达式被评估,它就会消失。它消失了。加入无形的合唱团。去见它的制造者。它成为一个前表达。

确实将一个const引用绑定到一个临时值可将临时值的范围扩展到封闭范围的末尾。

但是在这种情况下,表达式的范围是构造函数。当构造函数完成时,临时值被破坏。

您的编译器注意到表达式的const引用仍然继续存在,但是作为类成员。您的编译器建议您使用类成员现在会导致未定义的行为。你的编译器想成为你的朋友。您的编译器不希望您编写错误的代码,因此您可以从编译器中获得一些免费且友好的建议。

在另一种情况下,您添加了一些稍微复杂的代码。它仍然是未定义的行为,但代码现在已经足够复杂,编译器无法看到未定义的行为结果。但它仍然是一个错误。

编译器会在编译器看到它们时尝试警告您潜在的问题。不幸的是,编译器每次都找不到所有可能的潜在问题。但是,很明显,编译器会让你知道。

+2

投票给巨蟒 –

+0

绝对散文。 – erip

+0

你确定吗?如果是这样的话,就不可能有聪明的指针。 – Noidea

-1

它们的返回值不完全相同。 从cppreference.com

特别地,标准::举动产生x值表达式,用于标识 其参数吨。它正好等于一个static_cast到右值 参考类型。

现在,看着rvalue引用,我们看到第二例子对象“0”可以长寿:

右边的值可以被用来初始化一个右值参考,在这种情况下 的由右值标识的对象的生命周期将延长至参考范围结束的 。

这样的引用(右值引用)之后被分配给类成员_a,这是允许的,所以你没有错误。

此外,对临时变量的右值引用可用于移动构造函数,因此如果正在初始化的成员具有它,我看不到问题。然而,在C++中,你永远不知道什么时候未定义的行为会突然袭击你:)

+0

Cppreference解释了它解释寿命延长的地方。现在与你引用的句子联系起来。 – Cubbi

+0

@Cubby,对不起,现在链接了什么?我应该链接什么? – Noidea

+0

cppreference中的“扩展”一词现在可点击,并导致解释问题的页面。 – Cubbi