【问题标题】:Binding rvalue to non-const reference via pointer cast?通过指针转换将右值绑定到非常量引用?
【发布时间】:2011-02-21 00:47:04
【问题描述】:

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

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。

【问题讨论】:

  • 最近没有足够频繁地使用 C++ 来记住核心转储是否为您提供了有用的信息(如堆栈跟踪)。有没有办法提供该错误消息(可能在调试器下运行)?
  • 这不是纯 C++ 代码,而是 GNU C++。它使用 C99 复合文字功能。
  • @Johannes Schaub- 感谢您指出这一点 - 我正在翻阅规范,试图找出它为什么有效!
  • @Merlyn Morgan-Graham - 别在意关于使用原语的评论,那是我对其他事情的愚蠢。

标签: c++ reference g++ rvalue


【解决方案1】:

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

GCC不喜欢&amp;(Temp){42},抱怨我拿了一个临时的地址。这是一个关于它仍然接受但并不真正喜欢的无效代码的警告。对于其他明显错误的代码,如&amp;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”之前打印)。

【讨论】:

  • 有趣的是,如果我将 'a' 设为全局,我将不再收到警告,我想这是因为文字被赋予了全局范围,因此持续了程序的长度。但是,如果我将“int i”更改为指针并将“a”声明为A *a = &amp;(A){new int(0)};,即使在全局范围内也会收到警告。
【解决方案2】:

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

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

第 5.4/1 节将强制转换运算符讨论为

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

这似乎表明

(Temp){42}

产生一个右值,法律上不应允许您使用&amp;的地址。

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

【讨论】:

    【解决方案3】:

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

    error: taking address of temporary [-fpermissive]
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2013-08-01
      • 1970-01-01
      相关资源
      最近更新 更多