7

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

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。

4

3 回答 3

2

您的代码不是真正的 C++。它使用复合文字,这是 C99 功能。在 C99 中,它计算为一个左值,并且在那里获取文字的地址是完全可以的。将这个扩展集成到 C++ 中,GCC 似乎改变了它的规则并使其成为一个右值,更好地将它们的分类符合 C++ 的现有规则,用于也产生右值的通常强制转换。

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

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++ 中,对象已经在完整表达式的末尾被破坏,甚至在到达其块的末尾之前(“~B”在“main”之前打印)。

于 2011-02-21T01:07:49.013 回答
0

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

一元 & 运算符的结果是指向其操作数的指针。操作数应为左值或限定 ID。

第 5.4/1 节将铸造运算符讨论为

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

这似乎表明

(Temp){42}

产生一个右值,法律上不允许你使用 using 的地址&

众所周知,我之前在阅读规范时会犯错误,所以如果有人能证实这一点,那就太棒了。

于 2011-02-21T00:52:58.807 回答
0

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

error: taking address of temporary [-fpermissive]

当然,加上 -fpermissive,它会编译但会报错,但它仍然不会崩溃并打印正确的结果。我猜 GCC 在“允许”的条件下有点作弊。

于 2011-02-21T01:10:05.660 回答