C ++的known feature是const引用延长了从函数返回的临时对象的生命周期,但是对函数返回的临时对象的成员使用常量引用是否可以接受? / p>
示例:
#include <string>
std::pair<std::string, int> getPair(int n)
{
return {std::to_string(n), n};
}
int main(int, char*[])
{
const int x = 123456;
const auto& str = getPair(x).first;
printf("%d = %s\n", x, str.c_str());
return 0;
}
输出:
123456 = 123456
答案 0 :(得分:12)
是的,这段代码完全可以接受。根据标准,规则是([class.temporary]):
有两种情况下,临时状态被摧毁 不同点比完全表达结束。第一个背景 是在调用默认构造函数来初始化元素的时候 阵列。如果构造函数有一个或多个默认参数,则 破坏默认参数中创建的每个临时值 在构造下一个数组元素之前排序,如果有的话。
- 醇>
第二个上下文是引用绑定到临时的。该 引用绑定的临时或临时的 绑定引用的子对象的完整对象 坚持参考的一生......
正如您所看到的那样,突出显示的行清楚地表明对子对象的绑定引用是可以接受的,因为整个对象也必须延长其生命周期。
请注意,Conditional Formatting
确实有资格作为子对象[intro.object]:
- 对象可以包含其他对象,称为子对象。子对象可以 是一个成员子对象(9.2),一个基类子对象(第10条),或者 数组元素。不是任何其他对象的子对象的对象 被称为完整的对象。
醇>
答案 1 :(得分:7)
它定义明确。
来自标准:$12.2/6 Temporary objects [class.temporary]:
(强调我的)
引用绑定的临时值或临时值 绑定引用的子对象的完整对象 持续参考的生命周期
关于子主题,$1.8/2 The C++ object model [intro.object]:
(强调我的)
对象可以包含其他对象,称为子对象。子对象可以 是一个成员子对象([class.mem]),一个基类子对象(子句) [class.derived]),或数组元素。不是任何其他对象的子对象的对象称为完整对象。
first
必须引用并且它是std::pair
的成员子对象,因此临时std::pair
(即完整对象)的生命周期将是延长,代码应该没问题。
答案 2 :(得分:2)
正如我在评论中提到的那样:
临时的寿命应该延长 成员访问的生命周期(在这种情况下为str)。那说,你 通过复制获取返回值应该是正常的。 RVO将避免这样做 额外的副本。
从标准第12.2.5节:
第二个上下文是引用绑定到临时的。该 临时引用的临时或临时的 引用绑定到的子对象的完整对象 在参考文件的生命周期内持续存在,除了:
- 临时绑定到构造函数中的引用成员 ctor-initializer(12.6.2)一直存在,直到构造函数退出。
- 临时绑定到函数调用中的引用参数 (5.2.2)持续到完整表达完成 包含电话。
为了避免任何麻烦,我宁愿这样做:
auto m_p = getPair(x);
这是有效的,因为RVO
每个编译器必须为此情况做。{/ p>
答案 3 :(得分:-1)
这似乎在12.2 / 4-5中得到解决:
有两种情况下,临时状态被摧毁 不同于完整表达的结束点。首先 context ... [处理数组的东西]
第二个上下文是引用绑定到临时的。该 临时引用的临时或临时的 引用绑定到的子对象的完整对象 在参考文件的生命周期内持续存在,除了:
有四个异常处理引用成员的构造函数绑定,函数调用,通过引用返回的函数以及在new-initializers中绑定的引用。
这些情况都不适用,因此临时文件在完整陈述结束时被销毁,留下暂时引用的临时成员。
只是帮助编译器意识到它可以从临时的移动:const auto str = std::move(getPair(x).first);