Convert multimap to void pointer and then back to multimap

Viewed 175

I need to convert multimap into a void buffer, and pass it into a function where the multimap should be reconstructed.

I know there is easy way to simply pass the multimap, but I need to do via the void pointer so please look at my logic below:

using namespace std;

void reconstruct_mm(void *ptr, size_t len) {

    multimap<int, int> *mm = ptr;
    mm = (multimap<<int, int>*>malloc(len));

    *** print the following 10, 20, 30...

}

int main (void) {

    void *buffer;
    size_t buffer_len = 0;

    multimap <int, int> m;

    // fill in multimap with values
    m.insert(pair <int, int> (1, 10);
    m.insert(pair <int, int> (2, 20);
    m.insert(pair <int, int> (3, 30);

    // from this point I need your help, I only wrote logic what I expect from the program.

    buffer = &mm;
    buffer_len = sizeof(mm);

    reconstruct_mm(buffer, buffer_len);

}

Thank you in advance!

2 Answers

Technically, you could just use static_cast, without any memory allocation at all:

void reconstruct_mm(void *ptr/* Next argument unneeded:, size_t len*/) {

   multimap<int, int> *mm = static_cast<multimap<int, int> *>(ptr);

   // Use here mm as a multimap pointer regularly
   cout << mm->size() << '\n';

}

The only legitimate case I can think of for this is if you're bound by some legacy code, e.g., one requiring something like a callback with a void * interface. If that's not the case, considering something avoiding the void * to begin with.

If you need to clone the map inside the reconstruct_mm() function from a void* it can't be done a straight way because std::map / std::multimap is a non-linear associative container and its elements are spread over different parts of the heap memory (plus its direct object on the stack).

You have to write some kind of serialization and deserialization routines. A serialization would be a loop which reads the map key by key and stores subsequent keys along with their values in an allocated memory buffer. Then you can pass it by void* to the reconstruct_mm() and on the other side you do exactly opposite (deserialization) iterating over the buffer and inserting keys and values to a new map.

I let myself code it:

#include <map>
#include <memory>
#include <iostream>

void reconstruct_mm(void *ptr, size_t len)
{
    std::multimap<int, int> m;
    int* buffer {static_cast<int*>(ptr)};    

    for (int i {0}; i < len*2; i+=2)
    {        
        m.insert( std::pair<int, int>(buffer[i], buffer[i+1]) );
    }

    for (auto const & elem : m) //check the values
    {
        std::cout << elem.first << " " << elem.second << std::endl;
    }
}

int main(void)
{
    std::multimap <int, int> m;

    // fill in multimap with values
    m.insert( std::pair<int, int>(1, 10) );
    m.insert( std::pair<int, int>(2, 20) );
    m.insert( std::pair<int, int>(3, 30) );

    //smart pointer to release buffer's memory at the end (credits: Paul McKenzie)
    auto buffer {std::make_unique<int[]>(m.size()*2)}; //*2 - for key int + value int 

    int i {0};
    for (auto const & elem : m)
    {
        buffer[i++] = elem.first;
        buffer[i++] = elem.second;
    }    

    reconstruct_mm( static_cast<void*>(buffer.get()), m.size() );        
}
Related