const引用临时对象的成员

时间:2016-07-06 14:23:00

标签: c++ c++11 reference const language-lawyer

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

4 个答案:

答案 0 :(得分:12)

是的,这段代码完全可以接受。根据标准,规则是([class.temporary]):

  
      
  1. 有两种情况下,临时状态被摧毁   不同点比完全表达结束。第一个背景   是在调用默认构造函数来初始化元素的时候   阵列。如果构造函数有一个或多个默认参数,则   破坏默认参数中创建的每个临时值   在构造下一个数组元素之前排序,如果有的话。

  2.   
  3. 第二个上下文是引用绑定到临时的。该   引用绑定的临时或临时的   绑定引用的子对象的完整对象   坚持参考的一生......

  4.   

正如您所看到的那样,突出显示的行清楚地表明对子对象的绑定引用是可以接受的,因为整个对象也必须延长其生命周期。

请注意,Conditional Formatting确实有资格作为子对象[intro.object]:

  
      
  1. 对象可以包含其他对象,称为子对象。子对象可以   是一个成员子对象(9.2),一个基类子对象(第10条),或者   数组元素。不是任何其他对象的子对象的对象   被称为完整的对象。
  2.   

答案 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(即完整对象)的生命周期将是延长,代码应该没问题。

仅供参考:ClangGCC说是,VC说不。

答案 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);