Hi I am working with std::unordered map. I am dealing with a lot of inserts. The count of inserts is known ahead. I thought to optimize the memory by using the reserve methodand assuming it pre-allocates big chunk of memory for all future inserts. However I have noticed that it makes no difference for the times the map tries to allocate the memory.
See the example here . The number of allocations for both map which has reserved the number of inserts and the one who hasn't is the same?
Is there any way to reduce the number of allocations?
#include <string>
#include <unordered_map>
#include <iostream>
#include <vector>
using namespace std;
inline size_t AllocationCounter = 0;
template <typename T>
struct my_alloc {
using value_type = T;
my_alloc(){ };
template <typename U>
constexpr my_alloc(const my_alloc<U>& Other) noexcept { }
T* allocate(std::size_t n) {
AllocationCounter++;
return static_cast<T*>(::operator new (n * sizeof(T)));
}
template <typename... Args>
void construct(T* p, Args&&... args) {
new (p) T(std::forward<Args>(args)...);
}
void deallocate(T* p, std::size_t n) noexcept {
AllocationCounter --;
delete p;
}
void destroy(T* p) noexcept {
p->~T();
}
};
void with_reserve()
{
unordered_map<size_t,size_t, std::hash<size_t>, std::equal_to<size_t>, my_alloc<std::pair<const size_t, size_t>>> m1;
m1.reserve(1000); /// <------------------ RESERVATION ?
for (size_t i = 0; i < 1000; i++)
{
m1.insert({i,i});
}
printf("With reserve - %llu Allocations\n", AllocationCounter);
}
void without_reserve()
{
unordered_map<size_t,size_t, std::hash<size_t>, std::equal_to<size_t>, my_alloc<std::pair<const size_t, size_t>>> m1;
for (size_t i = 0; i < 1000; i++)
{
m1.insert({i,i});
}
printf("Without reserve - %llu Allocations\n", AllocationCounter);
}
int main()
{
with_reserve();
without_reserve();
}
Output:
With reserve - 1001 Allocations
Without reserve - 1001 Allocations
Expected: the number of allocation with reserve to be less that without.
unordered_flat_mapwhosereservestraight up allocates a big chunk of memory, there's also the standard library'sflat_mapthat you can technically reserve, but it hasO(logn)lookupstd::maphas O(logn) lookup too. Butstd::unordered_maphas O(1).std::vector<std::pair<Key,Value>>has expensive insertion and deletion but you can allocate all at once and lookup is as fast as in the map (if not faster because it fits in cache).