将multimap转换为void指针,然后再转回multimap

3

我需要将multimap转换为void缓冲区,并将其传递到一个函数中,该函数应重构multimap。

我知道有一种简单的方法可以直接传递multimap,但我需要通过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);

}

谢谢您的提前感谢!

1
为什么要使用malloc()?它不会构造你的multimap - Fred Larson
1
new multimap<int,int>(),这只是创建了一个新的对象。你为什么要分配一个新的map?你是想复制它吗?还是只想打印出它的值? - ChrisMM
1
我觉得你根本不需要分配内存。但是如果你确实需要,使用 new 是正确的方法。 - Fred Larson
但是使用 sizeof(multimap) 来测量 multimap 的内存大小,这是正确的方法吗?只使用指针 void 和该大小就足以在另一端重建吗? - mhibert
3
尝试一个实验。创建一个空的 std::multimap,然后打印它的 sizeof。然后加载它并再次尝试 sizeof。它会改变吗? - Fred Larson
显示剩余3条评论
2个回答

4

从技术上讲,您可以只使用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
你的假设是正确的,我受限于C接口之间,所以我必须通过C代码传递它,因为内存是复制的,所以大小也必须被传递,因此我确实需要multimap的整个字节大小。 - mhibert
3
@mhibert:不,我认为你并没有。std::multimap对象的大小是固定的。其内容的内存是在对象本身之外动态分配的。 - Fred Larson
@mhibert Fred Larson 是正确的。如果 API 要求,您可以传递大小,但在这里没有用处。 - Ami Tavory
1
如果API实际上复制了内存而不仅仅是传递指针,那么你就没办法了。这个副本不包含有效的对象,你无能为力。 - molbdnilo
2
@mhibert 你可以传递指针,但是由于multimap不是可平凡复制的,所以无法通过C API传递副本。 - Guillaume Racicot

1

如果您需要在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() );        
}

我认为你是接近真相的人。我尝试了之前的例子,但它们对我的情况不起作用。如果您能就multimap的序列化/反序列化提供一些逻辑,那将非常棒。谢谢 ;) - mhibert
@mhibert 序列化只是一个从/到流中读写的花哨词汇。如果你可以将 multimap 写入文件并读取回来,那么你就可以对其进行序列化。 - n. m.
我正在处理这个问题... 一旦我提供了解决方案或标记了最有帮助的答案,我会及时回复。 - mhibert
@n.m. https://en.wikipedia.org/wiki/Serialization 这并不一定是唯一的情况。 - bloody
int *buffer = new int[m.size()*2]; //2 == for key int + value int -- 你应该使用 std::vector,因为 reconstruct_mm 可能会抛出异常。 - PaulMcKenzie
@PaulMcKenzie 谢谢你的理解!我进行了编辑(实际上使用了独特指针,但清理的想法得以保留 :) - bloody

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接