I was doing some quick benchmark tests involving a std:vector. I start with a relatively small vector of 100 ints and call various methods for filling it with 1,000,000 ints. Most of my functions involve clearing the elements and adding the elements again or creating a new vector and moving or swapping it with the original vector. I also have a function that just resizes the vector and overwrites the elements.
You can see the functions in the code below. What's interesting is that resizing the vector and overwriting the elements is by far quickest. I thought that reserving the memory before pushing the elements would improve performance.
I know that std::vector::resize() will resize the vector to contain the new count. According to cppreference:
If the current size is less than count, additional elements are appended and initialized with copies of value.
resize() should be constructing 100 less ints than the other functions. So I'm surprised by the difference in speed. I thought resize() would allocate and initialize the new elements while reserve would just allocate the memory.
#include <algorithm> #include <chrono> #include <iostream> constexpr int InitialSize = 100; constexpr int NewSize = 1000000; void overwrite(std::vector<int>& v) { v.resize(NewSize); for (int i = 0; i < NewSize; ++i) { v[i] = i; } } void clear(std::vector<int>& v) { v.clear(); v.reserve(NewSize); for (int i = 0; i < NewSize; ++i) { v.push_back(i); } } void swap(std::vector<int> &v) { std::vector<int> vnew; vnew.reserve(NewSize); for (int i = 0; i < NewSize; ++i) { vnew.push_back(i); } v.swap(vnew); } void move(std::vector<int> &v) { std::vector<int> vnew; vnew.reserve(NewSize); for (int i = 0; i < NewSize; ++i) { vnew.push_back(i); } v = std::move(vnew); } int main() { { std::vector<int> v(InitialSize); std::iota(v.begin(), v.end(), 1); auto start = std::chrono::high_resolution_clock::now(); move(v); auto finish = std::chrono::high_resolution_clock::now(); std::chrono::duration<double, std::milli> elapsed = finish - start; std::cout << "Move - elapsed time: " << elapsed.count() << " ms" << std::endl; } { std::vector<int> v(InitialSize); std::iota(v.begin(), v.end(), 1); auto start = std::chrono::high_resolution_clock::now(); clear(v); auto finish = std::chrono::high_resolution_clock::now(); std::chrono::duration<double, std::milli> elapsed = finish - start; std::cout << "Clear - elapsed time: " << elapsed.count() << " ms" << std::endl; } { std::vector<int> v(InitialSize); std::iota(v.begin(), v.end(), 1); auto start = std::chrono::high_resolution_clock::now(); swap(v); auto finish = std::chrono::high_resolution_clock::now(); std::chrono::duration<double, std::milli> elapsed = finish - start; std::cout << "Swap - elapsed time: " << elapsed.count() << " ms" << std::endl; } { std::vector<int> v(InitialSize); std::iota(v.begin(), v.end(), 1); auto start = std::chrono::high_resolution_clock::now(); overwrite(v); auto finish = std::chrono::high_resolution_clock::now(); std::chrono::duration<double, std::milli> elapsed = finish - start; std::cout << "Overwrite - elapsed time: " << elapsed.count() << " ms" << std::endl; } return 0; } Output:
Move - elapsed time: 14.6284 ms Clear - elapsed time: 17.5072 ms Swap - elapsed time: 12.9111 ms Overwrite - elapsed time: 5.19079 ms Quick Bench results.
Can someone explain what's going on here?
resizecan use someavxoptimizedmemsetto initialize members more efficiently and batched, whilepush_backwill initialize them one by one.-O3) ?int. A non-trivial type will trigger different optimisation paths and yield wildly different results, I suspect. Also, always repeat your timing experiments manifold to gain confidence in the results. As a rule of thumb you shouldn't repeat the experiment less than 20 times. And you should pre-heat the test as suggested by other comments here.