通过指针转换将rvalue绑定到非const引用?

时间:2011-02-21 00:47:04

标签: c++ reference g++ rvalue

我不明白以下代码如何编译/不编译:

struct Temp
{
  int i;
};

int main(int argc, char * argv[])
{
   //Temp &ref1 = (Temp){42}; // Error, as expected
   Temp &ref2 = *(Temp*)&(Temp){42}; // A-OK
   std::cerr << ref2.i << std::endl;
   return 0;
}

我正在使用g ++ 4.4.4。

3 个答案:

答案 0 :(得分:2)

您的代码不是真正的C ++。它使用复合文字,这是一个C99功能。在C99中,它评估为左值,并且在那里获取文字的地址是完全正确的。将此扩展集成到C ++中,GCC似乎改变了它的规则并使其成为右值,更适合将它们分类为现有的C ++规则,以便生成rvalues。

GCC不喜欢&(Temp){42},抱怨我拿了一个临时的地址。这是一个关于无效代码的警告,它仍然接受但并不喜欢。对于&A()等其他明显错误的代码也给出了相同的警告,这是一个合法的函数式C ++转换,它也产生一个rvalue,因此不能用作address-of运算符的操作数。

GCC将复合文字整合到C ++中也会过早地破坏临时性,如下面的测试所示

#include <iostream>
struct B {
  ~B() {
    std::cout << "~B" << std::endl;
  }
};
struct A { int i; B b; };

int main() {
  A *a = &(A){0};
  std::cout << "main" << std::endl;
}

在C99中,文字引用的对象将在整个块中处于活动状态(它将具有自动存储持续时间)。在GNU C ++中,对象在完整表达式结束时已被破坏,甚至在其块结束之前(“〜”打印在“main”之前)。

答案 1 :(得分:0)

我可能会对此有所误解,但这看起来像是编译器中的一个错误。 C ++ ISO标准§5.3.1/ 2将&运算符讨论为

  

一元&amp;的结果operator是指向其操作数的指针。 操作数应为左值或限定ID。

§5.4/ 1节讨论了铸造操作符

  

表达式(T) cast-expression 的结果是T类型。如果T是引用类型,则结果为左值,否则结果为右值。

这似乎表明

(Temp){42}

生成左值,法律允许您不能使用&的地址。

我之前已经知道在阅读规范时会犯错误,所以如果有人能证实这一点会很棒。

答案 2 :(得分:0)

正如templatetypedef所说,它似乎是编译器中的一个错误。使用4.6.0版本的GCC进行编译时,它会给出:

error: taking address of temporary [-fpermissive]

当然,通过添加-fpermissive,它会编译但是抱怨,但它仍然不会崩溃并打印出正确的结果。我猜GCC在“宽容”条件下有点作弊。