将 RVO 对象传递给 std::vector::emplace_back
Pass RVO object to std::vector::emplace_back
考虑以下数组:
std::vector<Foo> arr;
arr.emplace_back(calculate_foo());
emplace_back
受益于消除临时对象,因为它的参数在新构造的元素上就地传递(所以这里 emplace_back 会触发移动或复制构造函数)Foo(foo)
上面的代码当然会在 calculate_foo
中创建一个临时对象,然后根据 Foo 的构造函数将其复制或移动到新数组。
有没有机会让它更快并消除临时对象?
您无法避免使用 emplace_back
为 Foo
的构造函数创建临时参数。如果您使用 Foo
类型的参数,那么它就是将传递给放置对象的构造函数的临时对象。在这种情况下,push_back
将同样有效。
要真正利用安置,您的类型需要有一个构造函数,该构造函数采用一些轻量级参数,可用于构造更昂贵的对象。这样,只有临时对象才是轻量级对象。为了直接从 return 值放置,该构造函数只能采用单个参数。
示例:
struct ExpensiveMove {
explicit ExpensiveMove(double d) {
std::cout << "construct\n";
std::fill(arr.begin(), arr.end(), d);
}
ExpensiveMove(const ExpensiveMove&) { std::cout << "expensive copy\n"; }
ExpensiveMove(ExpensiveMove&&) { std::cout << "expensive move\n"; }
ExpensiveMove& operator=(const ExpensiveMove&) { std::cout << "expensive copy ass\n"; return *this; }
ExpensiveMove& operator=(ExpensiveMove&&) { std::cout << "expensive move ass\n"; return *this; }
std::array<double, 1024> arr;
};
double calculate()
{
return 4.2;
}
int main() {
std::vector<ExpensiveMove> arr;
arr.emplace_back(calculate());
}
本例中没有 ExpensiveMove
类型的临时对象。有一个临时的替身,没关系。
考虑以下数组:
std::vector<Foo> arr;
arr.emplace_back(calculate_foo());
emplace_back
受益于消除临时对象,因为它的参数在新构造的元素上就地传递(所以这里 emplace_back 会触发移动或复制构造函数)Foo(foo)
上面的代码当然会在 calculate_foo
中创建一个临时对象,然后根据 Foo 的构造函数将其复制或移动到新数组。
有没有机会让它更快并消除临时对象?
您无法避免使用 emplace_back
为 Foo
的构造函数创建临时参数。如果您使用 Foo
类型的参数,那么它就是将传递给放置对象的构造函数的临时对象。在这种情况下,push_back
将同样有效。
要真正利用安置,您的类型需要有一个构造函数,该构造函数采用一些轻量级参数,可用于构造更昂贵的对象。这样,只有临时对象才是轻量级对象。为了直接从 return 值放置,该构造函数只能采用单个参数。
示例:
struct ExpensiveMove {
explicit ExpensiveMove(double d) {
std::cout << "construct\n";
std::fill(arr.begin(), arr.end(), d);
}
ExpensiveMove(const ExpensiveMove&) { std::cout << "expensive copy\n"; }
ExpensiveMove(ExpensiveMove&&) { std::cout << "expensive move\n"; }
ExpensiveMove& operator=(const ExpensiveMove&) { std::cout << "expensive copy ass\n"; return *this; }
ExpensiveMove& operator=(ExpensiveMove&&) { std::cout << "expensive move ass\n"; return *this; }
std::array<double, 1024> arr;
};
double calculate()
{
return 4.2;
}
int main() {
std::vector<ExpensiveMove> arr;
arr.emplace_back(calculate());
}
本例中没有 ExpensiveMove
类型的临时对象。有一个临时的替身,没关系。