使用memcpy复制对象时出现双重释放或损坏错误

Joh*_*lin 8 c++ struct memcpy

我有以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

事实证明,代码可以打印出结果.但是我该如何解决这个错误呢?

dbu*_*ush 17

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

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

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

std::string s1 = "hello";
printf("len=%zu, str=%s\n",s1.size(),s1.c_str());

// serialize
char *c = new char[s1.size()+1];
strcpy(c, s1.c_str());
printf("c=%s\n",c);

// deserialize
std::string s2 = c;
printf("len=%zu, str=%s\n",s2.size(),s2.c_str());
Run Code Online (Sandbox Code Playgroud)

您将对其他类对象执行类似的步骤.

  • @Johnnylin然后你需要在字节级决定该数据的格式,因为套接字提供了字节级管道.然后,您需要编写代码以将要发送的数据转换为您选择的格式,以便您可以发送它. (3认同)

Jes*_*uhl 12

你不能memcpy()像非POD结构那样test.你完全破坏了这个std::string成员.

必须使用复制构造函数来复制C++对象.

  • 我建议你谷歌"C++序列化". (5认同)
  • *VLA是非法的*更确切地说,它们是某些编译器(gcc和可能的clang)的非标准扩展,据说我没有看到任何VLA. (3认同)

Ish*_*led 6

你得到一个双重释放错误的实际原因被固定到的,而不是为您创造变量的新String对象的事实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;
}
Run Code Online (Sandbox Code Playgroud)