In order to save memory (I need a map which is both sorted by values and by keys), I store pointers (well, actually iterators, according to the answer in this SO question) to the keys of a sparsepp in an std::vector
and the sort the vector by the values of keys in the map:
size_t i = 0;
sorted_hashtable_pointer_.resize(hashtable_.size());
for (auto it = hashtable_.begin(); it != hashtable_.end(); it++)
{
sorted_hashtable_pointer_[i] = MapKeyPointer(it);
i++;
}
std::sort(sorted_hashtable_pointer_.begin(), sorted_hashtable_pointer_.end(),
[](MapKeyPointer a, MapKeyPointer b) { return *a < *b; });
where both hashtable_
and sorted_hashtable_pointer_
are members of a class.
This works well, just after the sorting (in the same method) I check whether the pointers (iterators) now point to the correct place and they do.
However, when I access the stored pointers (iterators) at a later point, they no longer point to the correct location. I didn't touch the hashtable_
in the meanwhile, but it looks like it has moved (most pointers still point to value locations, while some do not).
What am I doing wrong here? I, of course, do not insert / erase / ... to or from the map.
Edit: Here is a Minimal, Complete, and Verifiable example.
#include <sparsepp/spp.h>
#include <vector>
#include <stdint.h>
#include <algorithm>
#include <iostream>
struct MyHash {
size_t operator()(std::vector<uint8_t> vec) const
{
std::size_t seed = vec.size();
for(auto& i : vec) {
seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
struct MapKeyPointer
{
typedef spp::sparse_hash_map<std::vector<uint8_t>, std::vector<uint32_t>>::iterator iterator;
MapKeyPointer(iterator i) : it(i) {}
MapKeyPointer() {}
const std::vector<uint8_t>& operator*() const { return it->first; }
const std::vector<uint8_t>* operator->() const { return &it->first; }
iterator it;
};
class Test
{
public:
Test() : maps_(10), sorted_(10) {}
void Init()
{
for (uint32_t i = 0; i < 10; i++)
{
maps_[i] = spp::sparse_hash_map<std::vector<uint8_t>, int, MyHash>();
sorted_[i] = std::vector<MapKeyPointer>();
for (uint32_t j = 0; j < 10000; j++)
{
const std::vector<uint8_t> key
{
(uint8_t)(std::rand() % 255),
(uint8_t)(std::rand() % 255),
(uint8_t)(std::rand() % 255),
(uint8_t)(std::rand() % 255),
(uint8_t)(std::rand() % 255),
(uint8_t)(std::rand() % 255)
};
maps_[i][key] = std::rand();
}
}
}
void Sort()
{
for (size_t i = 0; i < 10; i++)
{
sorted_[i].resize(maps_[i].size());
size_t j = 0;
for (auto it = maps_[i].begin(); it != maps_[i].end(); it++)
{
sorted_[i][j] = MapKeyPointer(it);
j++;
}
std::sort(sorted_[i].begin(), sorted_[i].end(),
[](MapKeyPointer a, MapKeyPointer b) { return *a < *b; });
}
}
void Access()
{
for (size_t i = 0; i < 10; i++)
{
for (size_t j = 0; j < sorted_[i].size(); j++)
{
const std::vector<uint8_t> key = *sorted_[i][j];
std::cout << i << " " << j << " " << key.size() << std::endl;
}
}
}
private:
std::vector<spp::sparse_hash_map<std::vector<uint8_t>, int, MyHash>> maps_;
std::vector<std::vector<MapKeyPointer>> sorted_;
};
int main()
{
Test t;
t.Init();
t.Sort();
t.Access();
}