2013-04-03 48 views
4

我不知道当我有这样的功能,会发生什么C++ 11会发生什么?当函数返回

'temp'在被销毁之前被拷贝到一个临时的r值(超出范围)并且C++ 11可能被NRVO优化(所以'temp'的拷贝被直接写入返回目的地插槽)?

+4

复制最有可能通过C++ 03 *和* C++ 11中的NRVO消除。 – juanchopanza

+1

它可能是:a)如果移动ctor可用,则移动;或b)如果第一个不起作用,则复制。当然,(N)RVO可以同时应用两次。 – Xeo

+1

既然你不需要'b'的副本,第二个参数应该改成'const stringmap&b'。对于第一个,我建议将它移动到'temp',即'stringmap temp(std :: move(a));'。这不会破坏NRVO,所以返回值仍然是最优化的。 –

回答

7

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

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

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

+0

在'std :: unordered_map 的情况下是这样,没有任何东西被复制,但是如果返回类型不可移动,通常可以有一个副本。 – bames53

4

这通常会在没有任何特殊规则的情况下从temp复制到函数的返回值。但是,标准中有两条规则旨在改善这一点。第一个是,该拷贝可以被省略(12.8/31):比

在与类返回类型的函数返回语句,当表达是一种非挥发性的自动对象的名称

(其他一个功能或catch子句参数)用相同cvunqualified类型作为函数返回类型时,复制/移动操作可以通过直接构建自动物体插入函数的返回值

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

第二个问题是,由于这种情况下满足复制省略上述标准,它将首先被认为是移动(12.8/32):

当的复制操作的省音的标准是满足或将被满足,除了源对象是函数参数,并且要被复制的对象由左值指定的情况下,首先执行用于选择副本的构造函数的重载解析,就好像该对象由右值。

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

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

注意的是,类必须有一张移动或拷贝构造函数这个工作,即使移动或复制会被省略。

5

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

+1

在没有RVO的C++ 11中,它应该被移动,而不是被复制。 –