0

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();
}
Dänu
  • 5,791
  • 9
  • 43
  • 56
  • 1
    Can you edit to include a [mcve] (or as complete as it can get when requiring a non-standard header)? – Phil M Feb 26 '19 at 17:01
  • 1
    Hard to tell. Are you accessing `operator[]`? It may insert elements to the hash. – Michael Veksler Feb 27 '19 at 11:47
  • Like so often, creating the Minimal, Complete, and Verifiable example solved the problem for me. The key of the map was not `const`. Thank you both for your suggestions. I will update my question accordingly. If any of you want to answer it, go ahead, else I will do it myself. Thank you again. – Dänu Feb 27 '19 at 12:48

0 Answers0