3

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!

Fred Larson
  • 60,987
  • 18
  • 112
  • 174
mhibert
  • 67
  • 6
  • 1
    Why `malloc()`? It won't construct your `multimap`. – Fred Larson Oct 11 '19 at 12:56
  • Okay, what do you suggest instead? – mhibert Oct 11 '19 at 12:58
  • 1
    `new multimap()`, but this just creates a new one. Why are you allocating a new map? You want to copy it? Or just print its values? – ChrisMM Oct 11 '19 at 12:59
  • 1
    It doesn't appear to me that you need to allocate memory at all. But if you did, `new` would be the correct way to do it. – Fred Larson Oct 11 '19 at 13:00
  • But is it the correct way to measure the memory size of multimap with sizeof(multimap)? Would be enough the pointer void and this size to reconstruct on the other end? – mhibert Oct 11 '19 at 13:02
  • 3
    Try an experiment. Create an empty `std::multimap`, and then print the `sizeof` it. Then load it up and try `sizeof` again. Does it change? – Fred Larson Oct 11 '19 at 13:11
  • @mhibert *and pass it into a function where the multimap should be reconstructed* -- Casting the pointer is not reconstructing. To me, reconstructing the object means that you're getting an array or stream of information, creating an empty multimap, and then inserting into the new multimap the information from the array / stream. Doing magic on a pointer is far from reconstruction. – PaulMcKenzie Oct 11 '19 at 13:51
  • "I need to convert multimap into a void buffer". Why? What kind of API requires that? Please show some real code, and/or tell us a lot more about the thing you are trying to achieve. – n. m. could be an AI Oct 11 '19 at 14:16

2 Answers2

4

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.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • 1
    Your assumption is correct, I limited with C interface in between so I have to pass it via C code so the size also have to be passed as the memory is copied so I really do I need the whole size of multimap in bytes – mhibert Oct 11 '19 at 13:07
  • 3
    @mhibert: No, I don't think you do. The size of a `std::multimap` object is fixed. The memory for its contents is allocated dynamically outside the object itself. – Fred Larson Oct 11 '19 at 13:09
  • @mhibert Fred Larson is correct. You can pass the size if the API requires it, but there is no use for it here. – Ami Tavory Oct 11 '19 at 13:12
  • 1
    @mhibert If the API acually copies the memory instead of simply passing around a pointer, you're out of luck. The copy does not contain a valid object and there's nothing you can do about it. – molbdnilo Oct 11 '19 at 13:29
  • 2
    @mhibert You can pass the pointer around but you can't pass a copy throught the C API, since a multimap is not trivially copiable. – Guillaume Racicot Oct 11 '19 at 13:30
1

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() );        
}
bloody
  • 1,131
  • 11
  • 17
  • I think you are the one who is close to the truth. I have tried previous examples those doesn’t work for my case. If you would be great if you could drop some logic on serialisation/deserialisation of the multimap. Thanks ;) – mhibert Oct 11 '19 at 14:04
  • @mhibert Serialisation is just a fancy word for reading and writing from/to a stream. If you can write a multimap to a file and read it back, you can serialise it. – n. m. could be an AI Oct 11 '19 at 14:25
  • I am working on it... Once I will either provide my solution or mark the most helpful answer – mhibert Oct 11 '19 at 15:05
  • @n.m. https://en.wikipedia.org/wiki/Serialization It's not necessarily the only case. – bloody Oct 11 '19 at 15:13
  • `int *buffer = new int[m.size()*2]; //2 == for key int + value int` -- You should be using `std::vector`, as `reconstruct_mm` can potentially throw an exception. – PaulMcKenzie Oct 13 '19 at 14:20
  • @PaulMcKenzie Thanks for realizing! I edited (used actually a unique pointer instead but the clean-up idea is preserved:) – bloody Oct 14 '19 at 10:06