【问题标题】:Best way to use emplace_back to avoid move constructor call?使用 emplace_back 避免移动构造函数调用的最佳方法?
【发布时间】:2018-09-19 19:28:12
【问题描述】:

我刚刚了解了guaranteed copy elision in C++17。根据该问题的答案:

当您执行return T(); 时,这会初始化 通过prvalue 运行。由于该函数返回 T,因此没有临时 创建; prvalue 的初始化只是直接初始化 返回值。

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

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

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

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

除了执行g() 函数所做的事情之外,还有更优雅的方法来避免使用emplace_back 调用移动构造函数吗?

【问题讨论】:

    标签: c++ c++11 c++17 emplace


    【解决方案1】:

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

    你认为你这样做了,但你没有将它传递给函数。你给它一个prvalue作为参数,是的,但是emplace_back接受的是一组转发references。引用必须引用一个对象,因此是 temporary is materialized,并且已移动。

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

    【讨论】:

    • 所以当一个prvalue被传递给任何接受任何类型引用(const引用或rvalue引用)的函数时,必然会构造一个临时的?
    • @user2108462 - 是的。绑定到引用是发生临时实现的地方。它必须发生,这样我们才能得到被引用的对象。
    • @StoryTeller,啊,我的阅读理解失败了——评论本身实际上说的是prvalue。
    • 当然,调用v.emplace_back(f); 会很酷,即不要立即执行 f(),而是将工厂函数传递到 emplace 以在适当的时间执行。但是,对于一个简单的对象来说,一般地用 std::function 来做这件事就太过分了。
    • @GemTaylor - 你不能用表达式模板或等效技术做类似的事情吗?可能是?但是,如果没有样板文件就可以使用它会很好。
    猜你喜欢
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    • 2010-11-12
    • 2021-10-09
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多