为什么非常量引用不能绑定到临时对象?

新手上路,请多包涵

为什么不允许获取对临时对象的非常量引用,函数 getx() 返回?显然,这是 C++ 标准禁止的,但我对这种限制的目的感兴趣, 而不是对标准的引用

 struct X
{
    X& ref() { return *this; }
};

X getx() { return X();}

void g(X & x) {}

int f()
{
    const X& x = getx(); // OK
    X& x = getx(); // error
    X& x = getx().ref(); // OK
    g(getx()); //error
    g(getx().ref()); //OK
    return 0;
}

  1. 很明显,对象的生命周期不能成为原因,因为 C++ 标准 不禁止 对对象的常量引用。
  2. 很明显,上述示例中的临时对象不是常量,因为允许调用非常量函数。例如, ref() 可以修改临时对象。
  3. 此外, ref() 允许您欺骗编译器并获得指向此临时对象的链接,从而解决了我们的问题。

此外:

他们说“将一个临时对象分配给 const 引用会延长该对象的生命周期”和“尽管对非 const 引用什么也没说”。我的 附加问题。以下分配是否会延长临时对象的生命周期?

 X& x = getx().ref(); // OK

原文由 Alexey Malistov 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

来自 这篇关于右值引用的 Visual C++ 博客文章

… C++ 不希望您意外修改临时对象,但直接在可修改的右值上调用非常量成员函数是显式的,因此允许…

基本上,您不应该尝试修改临时对象,因为它们是临时对象并且现在随时都会死掉。允许您调用非常量方法的原因是,只要您知道自己在做什么并且明确说明(例如,使用 reinterpret_cast),欢迎您做一些“愚蠢”的事情。但是,如果您将一个临时对象绑定到一个非常量引用,您可以“永远”继续传递它,只是为了让您对对象的操作消失,因为在此过程中您完全忘记了这是一个临时对象。

如果我是你,我会重新考虑我的功能设计。为什么 g() 接受引用,它会修改参数吗?如果不是,请将其设为 const 引用,如果是,您为什么尝试将临时传递给它,您不在乎它是您正在修改的临时吗?为什么 getx() 还是临时返回?如果您与我们分享您的真实场景以及您想要完成的工作,您可能会得到一些关于如何做到这一点的好建议。

违背语言并愚弄编译器很少能解决问题——通常会产生问题。


编辑:解决评论中的问题:1) `X& x = getx().ref(); // OK x 什么时候会死?` - 我不知道,我不在乎,因为这正是我所说的“违背语言”的意思。该语言说“临时对象在语句结束时死亡,除非它们被绑定到 const 引用,在这种情况下,它们会在引用超出范围时死亡”。应用该规则,似乎 x 在下一条语句的开头已经死了,因为它没有绑定到 const 引用(编译器不知道 ref() 返回什么)。然而,这只是一个猜测。

  1. 我清楚地说明了目的:不允许修改临时变量,因为它没有意义(忽略 C++0x 右值引用)。问题“那么为什么我可以调用非常量成员?”是一个很好的答案,但我没有比我上面已经说过的更好的答案了。

  2. 好吧,如果我在 X& x = getx().ref(); 中的 x 是正确的—在语句末尾死去,问题就很明显了。

无论如何,根据您的问题和评论,我认为即使是这些额外的答案也不会让您满意。这是最后的尝试/总结:C++ 委员会认为修改临时对象没有意义,因此,他们不允许绑定到非 const 引用。可能还涉及到一些编译器实现或历史问题,我不知道。然后,出现了一些具体的案例,决定不顾一切,仍然允许通过调用非常量方法直接修改。但这是一个例外 - 通常不允许您修改临时文件。是的,C++ 通常就是这么奇怪。

原文由 sbk 发布,翻译遵循 CC BY-SA 4.0 许可协议

为什么C++ 常见问题解答(我的 粗体字)中讨论:

在 C++ 中,非 const 引用可以绑定到左值,而 const 引用可以绑定到左值或右值,但没有什么可以绑定到非 const 右值。那是 为了保护人们不改变在新值可以使用之前被破坏的临时值的值。例如:

 void incr(int& a) { ++a; }
int i = 0;
incr(i);    // i becomes 1
incr(0);    // error: 0 is not an lvalue

如果允许该 incr(0) 或者一些没有人见过的临时值将被递增,或者更糟糕的是 0 的值将变为 1。后者听起来很傻,但实际上在早期的 Fortran 编译器中存在这样的错误留出一个内存位置来保存值 0。

原文由 Tony Delroy 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏