在异常情况下将临时对象绑定到非 const 引用

4
我可以帮您翻译成中文。需要注意的是,在函数调用的情况下,临时变量只能与非const引用参数绑定。以下是一个例子:
class Simple{
    public: 
       int i;
       Simple(Simple &f)
       {
         i = f.i + 1;
       }
       Simple(int j)
       {
         i = j;
       }
  };

int main()
{
   Simple f1 = Simple(2);   // error no matching call fruit::fruit(fruit)...
   return 0;
}

由于我试图将临时对象与非const引用参数绑定,因此会出现错误。

情况2:

try
{
 throw e;
}
catch ( exception& e )
{
}

我了解到,当我们抛出异常时,实际传递给catch的是原始异常的副本,即创建了一个临时对象来传递到catch子句。
catch所做的是通过非const引用捕获该异常。这与我在CASE 1中展示的情况相反。
因此,我的问题如下:
1)是否有特定的场景允许将临时对象绑定到非const引用?
2)如果有,请考虑哪些因素来允许这些异常。

他的意思是“不允许”,正如代码示例所示。 - Mike C
1个回答

6
有没有特定情况下允许将临时变量绑定到非const引用的场景?
对于左值引用(即类型T&),是没有这种情况的。你不能将一个临时变量绑定到非const左值引用上,因为修改诸如42这样的字面量并没有什么意义。它们可以绑定到const左值引用上,因为这样就承诺不会修改与引用绑定的对象。
实际上,它们可以绑定到右值引用(T&&)上,但这与本主题无关。
如果有这种情况,那么在允许这些异常时考虑了哪些因素?
确实,临时对象不能绑定到非const左值引用,但对于异常对象有一定的规定:
从C++11标准中获取(最接近的草案n3337):
§15.1/3中说,throw-expression初始化一个临时对象,称为exception object,其类型由从throw操作数的静态类型中删除任何顶层cv限定符并将类型从“T的数组”或“返回T的函数”调整为“指向T的指针”或“指向返回T的函数的指针”,来确定。 临时对象是一个左值,并用于初始化匹配的handler变量(15.3)。 [...]

强调是我的

cppreference将其简化为:

与其他临时对象不同,当初始化catch子句参数时,异常对象被认为是一个lvalue参数,因此可以通过lvalue引用捕获,修改和重新抛出。

因此,在这种情况下,实际上可以将异常绑定到非const lvalue引用。


是的,我知道在异常情况下有一个例外。但我的问题是它是基于什么原则被选择的,或者是否还有其他类似的例外... - ravi
@ravi 设计这个规定的原因是为了允许修改并重新抛出异常,正如它所说的那样。我不知道还有其他例外情况。 - David G
@ravi 核心问题1299的解决方案似乎可以回答你的问题。 - user3920237
@0x499602D2 很棒的回答,我刚才还在想这个问题,已点赞。 - vsoftco
“修改像42这样的文字量并没有太多意义。”为什么在抛出42作为异常时不适用此规则?我不明白为什么在异常的上下文中使用文字量(一个临时初始化为文字量值的变量,我猜是这个意思)更有意义。 - François Andrieux
@FrançoisAndrieux 由于您无法通过右值引用捕获异常,因此我的理解是为了防止过度复制,因为 throw X() 是抛出异常的最常见方式。 - David G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接