在 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 规则内联,如果编译器的目标是符合标准,那么编译器的手就被束缚了。
简单的答案是否定的;省略不适用于完美转发。但这是 c++ 所以答案实际上是肯定的。
它需要一些样板文件:
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); }));
输出是对 A(int,int)
的一次调用。没有移动发生。在 c++17 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 c++14 中,移动被简单地省略了。
我在工作中看到很多代码,人们将 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 规则内联,如果编译器的目标是符合标准,那么编译器的手就被束缚了。
简单的答案是否定的;省略不适用于完美转发。但这是 c++ 所以答案实际上是肯定的。
它需要一些样板文件:
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); }));
输出是对 A(int,int)
的一次调用。没有移动发生。在 c++17 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 c++14 中,移动被简单地省略了。