Memcpy 导致块释放两次错误

Memcpy leading to block freed twice error

我有一张地图,正在根据需要进行填充。为了将地图的内容输出到另一个变量中,我正在使用 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;
}

对我做错了什么有帮助吗?

您不能使用 memcpy 复制 "deep" 结构(例如 apple)。你的 apple 结构很深的原因是因为它包含一个 std::string ,它在堆上有内存。当您使用 memcpy 复制 std::string 时,您正在复制指向堆的指针,但现在您有两个结构(一个 structbb 和映射中的一个指向堆上的同一内存.

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

structbb = it->second;

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

您还需要将此行移到 if(it != one.end() 块的保护范围内。否则,如果你得到 "value not Found",it->second 将是假的。

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

当您使用 std::copyapple 复制到另一个 apple 时,复制到的结构中的 std::string 将包含指向与复制自结构中的 std::string

因此,当结构被销毁时,两个 std::string 都会尝试释放相同的内存。这就是您收到 "block freed twice" 错误的原因。

正如 Paul R 在评论中指出的那样,解决方案是使用赋值来正确处理 std::string:

的复制
apple structbb = it->second;