【发布时间】:2021-01-28 11:32:23
【问题描述】:
在下面的示例中,对于普通旧数据 (POD) 结构,我看到元素分配(给定正确大小的向量)与 emplace_back(给定具有保留存储的向量)相比的性能优势。有人能详细说明这种差异来自哪里吗?
非常感谢您!
备注
- 这个问题是在一个更大的项目中提出的,下面只是一个 MWE
- 我确实查看了编译器资源管理器,但没有找到好的解决方案
- 我确实知道赋值仅因为结构是 POD 才有效,但我确实希望编译器能够优化开销,因为 C++ 应该具有零开销抽象
- 也欢迎对代码提出任何一般性建议,感谢您的意见:)
代码
#include <iostream>
#include <vector>
#include <chrono>
#include <numeric>
using std::cout;
using std::endl;
using std::vector;
using std::size_t;
typedef std::chrono::high_resolution_clock hrc;
typedef std::chrono::microseconds ms;
using std::chrono::duration_cast;
struct Data {
int x, y;
inline Data() noexcept: x(0), y(0) {}
inline Data(int x, int y) noexcept: x(x), y(y) {}
};
int main() {
constexpr size_t n = 1000000;
constexpr size_t reps = 5;
for (size_t rep = 0; rep < reps; rep++) {
{
vector<Data> vec;
vec.reserve(n);
auto t1 = hrc::now();
for (size_t i = 0; i < n; i++)
vec.emplace_back(i, -i);
auto t2 = hrc::now();
cout << "Emplace Back: " << duration_cast<ms>(t2 - t1).count() << " ms" << endl;
// Check
size_t sum = 0;
for (auto const &elem : vec)
sum += elem.x;
if (sum != ((n * (n - 1)) / 2))
return EXIT_FAILURE;
}
{
vector<Data> vec;
vec.resize(n);
auto t1 = hrc::now();
for (size_t i = 0; i < n; i++)
vec[i] = Data(i, i);
auto t2 = hrc::now();
cout << "Assign : " << duration_cast<ms>(t2 - t1).count() << " ms" << endl;
// Check
size_t sum = 0;
for (auto const &elem : vec)
sum += elem.x;
if (sum != ((n * (n - 1)) / 2))
return EXIT_FAILURE;
}
}
}
输出
sysctl -n machdep.cpu.brand_string && clang++ -v && clang++ -o main -std=c++17 -O3 main.cpp && ./main
Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Emplace Back: 6162 ms
Assign : 1000 ms
Emplace Back: 2874 ms
Assign : 864 ms
Emplace Back: 2149 ms
Assign : 855 ms
Emplace Back: 2062 ms
Assign : 934 ms
Emplace Back: 2678 ms
Assign : 1030 ms
【问题讨论】:
-
我会说一个位置作为两个操作:分配值并增加向量的“虚拟”大小,而分配只是分配
-
你为什么在测量中忽略了
vec.reserve(n);和vec.resize(n);?这是两个版本之间的重要区别。之后结果非常相似:ideone.com/G1mXty -
@mch 如果我在 ideone 网站上使用他的代码,我得到的时间也非常相似(不考虑保留和调整大小),所以它似乎也可能取决于平台
-
与您的问题无关。如果在类体内定义了成员函数(或构造函数),则无需在它们前面添加
inline,因为它们是隐式内联的。 -
所以我有类似的结果,甚至删除 vec.reserve(n) 并使用 push_back 代替分配! emplace_back 的性能较低!
标签: c++ performance stl