Glyphi
Glyphi

Reputation: 11

What should I pass as allocator to a std::hash_map?

I have created a little class and am trying to use it as the data in an STL hash_map. Lots of searching has got me as far as knowing I need to add stuff as the Allocator, but so far I have seen no examples of how to use the default allocators in STL in my class. Could someone help and show me please? I've put a reduced version of my class below.

class cwVariable {

public:
    cwVariable();
    template <typename T>
    cwVariable(T value)
    {
        stash = new byte[sizeof(T)];
        memcpy(stash, &value, sizeof(T));
    }

    template <typename T>
    void set(T value)
    {
        if (stash != 0) {
            memcpy(stash, &value, sizeof(T));
        }
    }

    template <typename T>
    T get()
    {
        T out;
        memcpy(&out, stash, sizeof(T));
        return out;
    }
    ~cwVariable();
private:
    void * stash = 0;
};


cwVariable::~cwVariable() {
    delete stash;
}

For completeness: I'm using the Arduino 1.6.4 toolchain, the STL from a port for Arduino and targetting an Arduino Mega 2560. Using the Visual Micro add-in for Visual Studio 2012.

Added later: My real code handles more than above, but just C type string pointers, not String. The trail started when I added

std::hash_map<const char*, cwVariable> months; 

to my code and got the output

cwVar.cpp.o:In function `std::hash_map<char const*, cwVariable, std::hash<char const*>,
std::equal_to<char const*>, std::allocator<cwVariable> >::operator[](char const* const&)'
stl_hash_map.h:cwVariable()' 
collect2.exe*:error: ld returned 1 exit status as the error.

This made me research more and got me worried about allocators.

Upvotes: 0

Views: 327

Answers (2)

David Hammen
David Hammen

Reputation: 33116

You don't need an allocator. Those are for when you are doing your own memory management (e.g., a memory pool). What you do need, and what your class does not have, is a working deep copy constructor. Your class instead has the freebie shallow copy constructor. This will copy the pointer rather than the contents of the pointer.

As is, your class doesn't contain the necessarily information to know how to copy construct an instance. One way to solve this would be to store the size of the allocated type as a data member. The copy constructor will allocate a stash of the right size and memcpy the source stash to the new stash of the new instance.

A much better approach would be to make the entire class a class template, and this goes after an underlying problem with your design. Your use of void* and memcpy are a recipe for future problems. As is, your class works for POD classes, but not much else.

If you templatize the entire class and change void* stash to T stash, the freebie copy constructor is exactly what you want. If you change the void* stash to T* stash, you will have to provide a copy constructor, but it's rather simple. In both cases, your get and set member functions are trivial, and your code is much more generic than is your current void* stash / memcpy implementation.

Upvotes: 2

SergeyA
SergeyA

Reputation: 62563

Simply using your class as a data type in hash_map does not require you to have an allocator. You only need allocator if you want to implement specific allocation policy for your map.

Upvotes: 0

Related Questions