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