C ++ 11函数返回时会发生什么

时间:2013-04-03 16:45:33

标签: c++ c++11

我想知道当我有这样的功能时会发生什么:

typedef std::unordered_map<std::string,std::string> stringmap;

stringmap merge (stringmap a,stringmap b) 
{
  stringmap temp(a); temp.insert(b.begin(),b.end()); return temp;
}

函数返回时会发生什么?

'temp'是否在被销毁之前被复制到临时r值(超出范围)并且C ++ 11可能被NRVO优化(因此'temp'的副本直接写入返回目标槽)?

3 个答案:

答案 0 :(得分:7)

不应复制任何内容。有两种可能性:

  • temp被移动到调用者范围内的对象;或
  • 移动被省略,temp成为调用者范围内对象的别名。这被称为“返回值优化”。

2011年之前(具体而言,没有移动语义),第一种情况需要复制而不是移动。第二种情况在C ++ 98和11中都被允许。

答案 1 :(得分:5)

NRVO意味着temp本身是在返回值位置构建的。没有RVO,是的,temp被复制/移动到堆栈上的位置,然后被销毁到返回值位置。

答案 2 :(得分:4)

这通常会在没有任何特殊规则的情况下导致从temp复制到函数的返回值。但是,标准中有两条旨在改进这一规则的规则。首先是可以省略副本(12.8 / 31):

  

在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cvunqualified类型的非易失性自动对象(函数或catch子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值

中,可以省略复制/移动操作

这通常被称为命名返回值优化(NRVO),return value optimization (RVO)的一个特例。

第二个是,由于这种情况符合上述复制标准的标准,它将首先被视为一个移动(12.8 / 32):

  

当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就像对象是由右值指定一样。

因此编译器将尝试以下步骤:

  • 该类是否有移动构造函数?
    • 如果是这样,要么移动要么移动。
    • 如果没有,该类是否有复制构造函数?
      • 如果是这样,请移动它或者删除副本。
      • 如果没有,我们无法复制或移动此对象。

请注意,即使删除了移动或复制,该类也必须具有移动或复制构造函数才能生效。