Memcpy导致块释放两次错误

时间:2015-03-04 08:04:17

标签: c++ c++11 dictionary std memcpy

我有一张我根据需要填写的地图。要将地图的内容输出到另一个变量中,我使用的是memcpy。

如果memcpy行被注释,我看到输出打印正确显示。 100 => 1234水果

如果我取消注释memcpy,我会看到以下错误。之前看到的打印也不会显示。

块释放两次

退出:ExitFailure 127

#include <iostream>
#include <map>
#include <string>

struct apple
{
    int iValue;
    std::string str1;
};

typedef std::map<int, apple> AppleMap;

int main()
{
    AppleMap one;
    apple structaa;
    structaa.iValue = 1234;
    structaa.str1 = "Fruits";
    int value = 100;
    one[value]=structaa;

    AppleMap::iterator it = one.find(100);
    if(it != one.end())
    {
        std::cout << it->first << " => " << it->second.iValue << '\t' << it->second.str1 << '\n';
    }
    else
    {
        std::cout << "Value Not Found\n";
    }

    apple structbb; 
    memcpy(&structbb, &(it->second), sizeof(apple));

    return 0;
}

我做错了什么帮助?

2 个答案:

答案 0 :(得分:4)

您无法使用apple复制“深层”结构(例如memcpy)。你的apple结构深度的原因是它包含一个std::string,它在堆上有内存。当您使用memcpy复制std::string时,您正在复制指向堆的指针,但现在您有两个结构(一个structbb和一个在地图内指向堆上的相同内存

正确的做法是直接复制structbb,不要使用memcpy,即

structbb = it->second;

这将使用默认的复制方法,该方法将使用他们的定义的复制方法复制每个成员。字符串成员str1的默认复制方法是安全的,这意味着复制的字符串指向 new 堆内存位置,以便可以安全地销毁旧字符串而不会影响新字符串

您还希望将此行移至if(it != one.end()块的保护范围内。否则,如果您收到“未找到值”,it->second将是假的。

答案 1 :(得分:1)

在内部,std::string存储指向堆内存的指针。

使用appleapple复制到另一个std::copy时,复制到结构中的std::string将包含指向与{相同的内存位置的指针复制的结构中的{1}}。

因此,当结构被破坏时,std::string都会尝试释放相同的内存。这就是为什么你得到“块释放两次”的错误。

正如Paul R在评论中指出的那样,解决方案是使用能正确处理std::string复制的作业:

std::string