在 emplace() 中创建对象时复制省略

Copy elision when creating object inside emplace()

我在工作中看到很多代码,人们将 emplace 和 emplace_back 与临时对象一起使用,例如:

struct A {
    A::A(int, int);
};

vector<A> v;
vector<A>.emplace_back(A(1, 2));

我知道emplace_back的重点是能够直接传递参数,像这样:

v.emplace_back(1, 2);

但不幸的是,少数人并不清楚这一点。但让我们不要纠缠于此....

我的问题是:编译器是否能够对此进行优化并跳过创建和复制?或者我真的应该尝试解决这些问题吗?

供您参考...我们正在使用 C++14。

is the compiler able to optimize this and skip the create and copy?

不一定涉及文案。如果移动构造函数可用,就会有一个移动。这不能被优化掉,因为直接初始化的情况只会调用 init 构造函数,而在另一种情况下,移动构造函数将被额外调用(包括它的副作用)。

因此,如果可能,您应该重构该代码。

My question is: is the compiler able to optimize this and skip the create and copy? Or should I really try to fix these occurrences?

在一般情况下,它无法避免复制。由于 emplace_back 通过转发引用接受,它必须从纯标准的角度创建临时对象。毕竟,这些引用必须绑定到对象。

复制省略是一组规则,允许避免复制(或移动)构造函数,并省略复制,即使构造函数和相应的析构函数有副作用。它仅适用于特定情况。通过引用传递参数不是其中之一。因此,对于非平凡的类型,对象副本不能被 as-if 规则内联,如果编译器的目标是符合标准,那么编译器的手就被束缚了。

简单的答案是否定的;省略不适用于完美转发。但这是 所以答案实际上是肯定的。

它需要一些样板文件:

struct A {
  A(int, int){std::cout << "A(int,int)\n"; }
  A(A&&){std::cout<<"A(A&&)\n";}
};

template<class F>
struct maker_t {
  F f;
  template<class T>
  operator T()&&{ return f(); }
};

template<class F>
maker_t<std::decay_t<F>> maker( F&& f ) { return {std::forward<F>(f)}; }

vector<A> v;
v.emplace_back(maker([]{ return A(1,2); }));

live example.

输出是对 A(int,int) 的一次调用。没有移动发生。在 the making doesn't even require that a move constructor exist (but the vector does, as it thinks it may have to move the elements in an already allocated buffer). In 中,移动被简单地省略了。