我不明白以下代码如何编译/不编译:
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。
答案 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在“宽容”条件下有点作弊。