使用内存复制对象时出现双自由或损坏错误

double free or corruption error when copying object with memcpy

本文关键字:自由 损坏 错误 内存 复制 对象      更新时间:2023-10-16

我有以下代码:

#include <iostream>
#include <string>
#include <cstring>
struct test {
    std::string name;
    size_t id;
};

int main() {
    test t;
    t.name = "147.8.179.239";
    t.id = 10;
    char a[sizeof(t)] = "";
    std::memcpy(a, &t, sizeof(t));
    test b;
    std::memcpy(&b, a, sizeof(t)); 
    std::cout << b.name << " " << b.id << std::endl;
}

当我编译并运行它时,它给了我以下错误:

147.8.179.239 10
*** Error in `./test': double free or corruption (fasttop): 0x0000000000bf9c20 ***
Aborted (core dumped)

结果证明代码可以打印出结果。但是我该如何修复这个错误呢?

按您的方式使用memcpy,您有两个完全相同的std::string对象。这包括它们可能在内部使用的任何指针。因此,当每个对象的析构函数运行时,它们都试图释放同一个指针。

这就是为什么你需要使用复制构造函数或将一个分配给另一个(即使用覆盖的operator=)。它知道这些实现差异并正确处理它们,即为目标对象分配一个单独的内存缓冲区。

如果要提取std::string中包含的字符串,则需要对象序列化为已知的表示形式。然后你可以反序列化来转换它。

std::string s1 = "hello";
printf("len=%zu, str=%sn",s1.size(),s1.c_str());
// serialize
char *c = new char[s1.size()+1];
strcpy(c, s1.c_str());
printf("c=%sn",c);
// deserialize
std::string s2 = c;
printf("len=%zu, str=%sn",s2.size(),s2.c_str());

对其他类对象执行类似的步骤

您不能像test那样memcpy()非pod结构体。你完全破坏了std::string成员。

必须使用复制构造函数来复制c++对象。

你得到一个双自由错误的实际原因是固定的事实,而不是为你的变量ab创建一个新的字符串对象,你只是复制引用(string对象是使用可变长度char *实现的)。

由于string析构函数在程序结束时释放了这个内存地址,并且如上所述,有两个字符串对象指向同一个地址,因此会得到一个双自由度错误

这将工作,就像@JesperJuhl说的,你必须使用复制构造函数

#include <iostream>
#include <string>
#include <cstring>
struct test
{
    std::string name;
    size_t id;
};

int main()
{
    test t;
    test a;
    test b;
    t.name = "147.8.179.239";
    t.id = 10;
    a=t;
    b=t;
    std::cout << b.name << " " << b.id << std::endl;
}