4

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

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' 的副本直接写入返回目标插槽)?

4

3 回答 3

7

什么都不应该被复制。有两种可能:

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

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

于 2013-04-03T16:52:44.370 回答
5

NRVO 意味着它temp本身是在返回值位置构造的。如果没有 RVO,是的,temp它会在被销毁之前从堆栈上的位置复制/移动到返回值位置。

于 2013-04-03T16:50:26.990 回答
4

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

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

这通常称为命名返回值优化 (NRVO),是返回值优化 (RVO)的一种特殊情况。

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

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

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

  • 该类是否有移动构造函数?
    • 如果是这样,要么移动它,要么忽略移动。
    • 如果没有,该类是否具有复制构造函数?
      • 如果是这样,请移动它或删除副本。
      • 如果没有,我们不能复制或移动这个对象。

请注意,该类必须具有移动或复制构造函数才能使其工作,即使移动或复制被省略。

于 2013-04-03T16:49:50.020 回答