"Most important const"条件表达式?

"Most important const" with conditional expression?

本文关键字:表达式 条件 const Most important      更新时间:2023-10-16

考虑以下代码:

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();
}

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

问题二:

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

根据测试,对1的答案几乎肯定是"是"。我不太确定,不过(复制省略之类的)…似乎有可能条件表达式最终会从*aPtr复制构造一个临时的MyClass,并延长临时的 的寿命。

条件表达式是一个右值(因为它的一个操作数是右值)。如果选择了条件操作符的第一个可选项,则将其转换为临时操作符(这会导致复制)。该临时对象绑定到引用,并应用通常的生命周期扩展。

相关标准[expr.cond]:

如果操作数具有类类型,则结果是结果类型的右值临时值,根据第一个操作数的值从第二个操作数或第三个操作数复制初始化。

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

在两种上下文中,临时变量在fulexpression末尾的不同位置被销毁。第一个上下文是在调用默认构造函数[…]

时。

第二个上下文是当引用绑定到临时对象时。引用所指向的临时对象引用被绑定到的子对象的完整对象(即临时对象)持续存在引用的生命周期,除了:

  • 在构造函数的参数初始化式[…]
  • 中临时绑定到引用成员
  • 函数调用中临时绑定到引用参数[…]
  • 函数返回语句中临时绑定返回值的生命周期[…]
  • new-initializer[…]
  • 中临时绑定到引用

这些例外都不适用。

如果aPtr是一个有效的指针,那么由于aPtr ? *aPtr : MyClass{}的类型只是MyClass,因此进行复制。该临时对象被绑定到a,并且生命周期也出于同样的原因而持续存在。

关于1)见上面kerek的回答

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

5.16/4:如果第二个和第三个操作数是相同值类别的glvalue,并且具有相同类型,则结果为该类型和值类别(…)。

5.16/5:否则,结果为右值。(…)

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

Edit:这里有一个在线演示,它显示const引用引用的是一个临时对象,而不是aPtr指向的原始对象。