19

我刚刚了解了 C++17 中的保证复制省略。根据该问题的答案:

当你这样做时return T();,这将通过 a 初始化函数的返回值prvalue。由于该函数返回 T,因此不会创建临时函数;的初始化prvalue简单直接初始化返回值。

要理解的是,由于返回值是 a prvalue,它还不是一个对象。它只是一个对象的初始化器,就像T()is 一样。

所以我想知道,这是否适用于:

T f() {return T();}
T t = f();

所以我写了这段代码emplace_back来测试它:

#include <vector>
#include <iostream>
struct BigObj{
  BigObj() = default;
  BigObj(int) { std::cout << "int ctor called" << std::endl;  }
  BigObj(const BigObj&){
    std::cout << "copy ctor called" << std::endl;
  }
  BigObj(BigObj&&){
    std::cout << "move ctor called" << std::endl;
  }
};
BigObj f(){ return BigObj(2); }
int g(){ return 2; }
int main(){
  std::vector<BigObj> v;
  v.reserve(10);
  std::cout << "emplace_back with rvalue \n";
  v.emplace_back(1+1);
  std::cout << "emplace_back with f()\n";
  v.emplace_back(f());
  std::cout << "emplace_back with g()\n";
  v.emplace_back(g());
}

这是我得到的输出(禁用复制省略):

emplace_back with rvalue 
int ctor called
emplace_back with f()
int ctor called
move ctor called
emplace_back with g()
int ctor called

似乎移动构造函数仍然被调用,即使 aprvalue被直接传递给emplace_back,我认为它可以用来直接构造一个对象,而不是用来构造一个临时的然后移动它。

有没有更优雅的方法来避免移动构造函数调用,emplace_back而不是像函数一样做一些事情g()

4

1 回答 1

22

即使将prvalue直接传递给emplace_back,似乎仍然调用移动构造函数

你认为你这样做了,但你没有将它传递函数。你给它一个prvalue作为参数,是的,但是emplace_back接受的是一组转发引用。引用必须引用一个对象,因此临时对象被物化和移动。

正确的使用方法是向它传递参数以在适当的位置emplace_back初始化对象。这样您就不需要移动向量的元素类型(尽管您可能需要移动/复制参数)。

于 2018-04-10T08:47:35.547 回答