Преобразование мультикарты в пустой указатель, а затем обратно в мультикарту - PullRequest
3 голосов
/ 11 октября 2019

Мне нужно преобразовать мультикарту в пустой буфер и передать ее в функцию, где мультикарта должна быть восстановлена.

Я знаю, что есть простой способ передать мультикарту, но мне нужно сделать это с помощью указателя void, поэтому, пожалуйста, посмотрите на мою логику ниже:

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);

}

Заранее спасибо!

Ответы [ 2 ]

4 голосов
/ 11 октября 2019

Технически, вы можете просто использовать static_cast, без какого-либо выделения памяти:

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';

}

Единственный законный случай, который я могу придумать, это если высвязанный некоторым устаревшим кодом, например, требующим что-то вроде обратного вызова с интерфейсом void *. Если это не так, подумайте о том, чтобы не начинать с void *.

1 голос
/ 11 октября 2019

Если вам нужно клонировать карту внутри функции reconstruct_mm() из void*, это нельзя сделать прямым способом, поскольку std::map / std::multimap является нелинейным ассоциативным контейнером и его элементы распределеныпо разным частям кучи (плюс ее прямой объект в стеке).

Вы должны написать какие-то подпрограммы сериализации и десериализации. Сериализация была бы циклом, который считывает ключ карты по ключу и сохраняет последующие ключи вместе с их значениями в выделенном буфере памяти. Затем вы можете передать его по void* на reconstruct_mm(), а с другой стороны вы делаете абсолютно противоположную (десериализацию) итерацию по буферу и вставку ключей и значений в новую карту.

Я позволил себе закодировать это:

#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() );        
}
...