"Most important const" 有条件表达式?

"Most important const" with conditional expression?

考虑以下代码:

int foo(MyClass const* aPtr = 0) {
    MyClass const& a = aPtr ? *aPtr : MyClass(); // Either bind to *aPtr, or to a default-constructed MyClass
    ...
    return a.bar();
}

"most important const" 希望在这里使用。目的是允许传入一个 null aPtr(顺便说一句,是的,它必须是一个指针参数),在这种情况下,一个临时的 MyClass 对象将被默认构造,并且它的生命周期通过绑定到它的 const 引用扩展。然而,如果 aPtr 不为空,则引用将绑定到其指向的对象,而不会发生任何(昂贵的)复制构造。

两个问题是:

  1. 如果 aPtr == 0a 是否保证在函数结束之前引用有效的 MyClass 对象?
  2. 如果 aPtr != 0a 会绑定到它,而不是其他一些 MyClass 吗?

根据测试,1 的答案几乎可以肯定是 "yes"。 #2 我不太确定,虽然(复制省略等)......条件表达式似乎最终可能会从 *aPtr 复制构造一个临时 MyClass,并扩展的生活是暂时的。

首先,是的 a 保证引用有效的 MyClass 对象。这直接来自 [class.temporary]/4-5:

There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when a default constructor is called [...]

The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:

  • A temporary bound to a reference member in a constructor’s ctor-initializer [...]
  • A temporary bound to a reference parameter in a function call [...]
  • The lifetime of a temporary bound to the returned value in a function return statement [...]
  • A temporary bound to a reference in a new-initializer [...]

None 这些例外情况适用。

如果 aPtr 是一个有效的指针,那么会创建一个副本,因为 aPtr ? *aPtr : MyClass{} 的类型只是 MyClass。该临时文件绑定到 a,并且 它的 生命周期也出于同样的原因而持续存在。

您的条件表达式是纯右值(因为它的操作数之一是)。如果选择了条件运算符的第一个替代项,则将其转换为临时项(产生副本)。该临时绑定到引用,并且适用通常的生命周期扩展。

相关标准语[expr.cond]:

If the operands have class type, the result is a prvalue temporary of the result type, which is copy-initialized from either the second operand or the third operand depending on the value of the first operand.

关于 1) 请参阅上面 kerek 的回答

关于2)标准中关于条件运算符的说法:

5.16/4: If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category (...).

5.16/5: Otherwise, the result is a prvalue. (...)

根据 3.10/1 中左值和右值的分类,*aPtr 是左值,MyClass() 是纯右值。因此,结果应该是一个纯右值,这样引用就应该引用这个临时文件(可能是一个复制构造的临时文件)。

编辑: 这里有一个online demo,这表明const引用是指临时的而不是原始的aPtr 指向的对象。