请考虑以下代码:
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();
}
该 “最重要的常数” 希望在这里使用。目的是允许null aPtr
传入(BTW,是的,它必须是指针参数),在这种情况下是临时的 MyClass
object将是默认构造的,并且它的生命周期由const引用绑定到它。然而,如果 aPtr
如果不为null,引用将绑定到其指向的对象,而不会发生任何(昂贵的)复制构造。
问题二是:
- 如果
aPtr == 0
是的 a
保证引用有效 MyClass
对象直到函数结束?
- 如果
aPtr != 0
,将 a
绑定它,而不是其他一些 MyClass
?
根据测试,1的答案几乎肯定是“是”。 #2我不太确定,但是(复制省略等)......条件表达式似乎有可能最终复制构造一个临时的 MyClass
从 *aPtr
,延长寿命 那 临时。
您的条件表达式是一个prvalue(因为它的一个操作数是)。如果选择了条件运算符的第一个替代项,则将其转换为临时(产生副本)。该临时性与参考绑定,并且适用通常的生命期延长。
相关标准[expr.cond]:
如果操作数具有类类型,则结果是结果类型的prvalue临时值,它根据第一个操作数的值从第二个操作数或第三个操作数进行复制初始化。
首先,是的 a
保证是指有效的 MyClass
目的。这直接来自[class.temporary] / 4-5:
在两种情况下,临时表在与完全表达结束时不同的地方被摧毁。第一个上下文是在调用默认构造函数时[...]
第二个上下文是引用绑定到临时的。引用的临时值
绑定或临时,它是绑定引用的子对象的完整对象 仍然存在
在参考的生命周期 除:
- 临时绑定到构造函数中的引用成员 构造函数初始化程序 [...]
- 临时绑定到函数调用中的引用参数[...]
- 在函数返回语句中临时绑定到返回值的生命周期[...]
- 临时绑定到a中的引用 新初始化 [...]
这些例外都不适用。
如果 aPtr
是一个有效的指针,然后复制是因为类型 aPtr ? *aPtr : MyClass{}
只是 MyClass
。这种临时性受到约束 a
,和 它的 一生也因同样的原因而持续存在。
关于1)见上面的kerek答案
关于2)标准说关于条件运算符:
5.16 / 4: 如果第二个和第三个操作数是glvalues的 相同的价值类别 并拥有 相同的类型,结果是该类型和值类别(...)。
5.16 / 5: 否则,结果是prvalue。 (......)
根据中国的左撇子和左撇子的分类 3.10 / 1, *aPtr
是一个左值, MyClass()
是一个prvalue。因此,结果应该是一个prvalue,以便引用应该引用此临时(可能是复制构造的temp)。
编辑: 在这里 在线演示,这表明const引用引用了一个临时的而不是指向aPtr指向的原始对象。