使用 memcpy 复制对象时出现双重释放或损坏错误
double free or corruption error when copying object with 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;
}
当我编译它并运行它时,它给了我以下错误:
147.8.179.239 10
*** Error in `./test': double free or corruption (fasttop): 0x0000000000bf9c20 ***
Aborted (core dumped)
原来代码可以打印出结果。但是我该如何解决这个错误呢?
您不能 memcpy()
像 test
这样的非 POD 结构。你完全破坏了 std::string
成员。
您必须使用复制构造函数来复制 C++ 对象。
按照您现在的方式使用 memcpy
,您将拥有两个完全相同的 std::string
对象。这包括它们可能在内部使用的任何指针。因此,当每个对象的析构函数运行时,它们都试图释放同一个指针。
这就是为什么您需要使用复制构造函数或将一个构造函数分配给另一个构造函数(即使用重写的 operator=
)。它知道这些实现差异并正确处理它们,即它为目标对象分配一个单独的内存缓冲区。
如果要提取 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());
您可以对其他 class 个对象执行类似的步骤。
你得到双重释放错误的真正原因是这样一个事实,而不是为你的变量 a
和 b
创建一个新的字符串对象,你只是复制引用 ( 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;
}
我有以下代码:
#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()
像 test
这样的非 POD 结构。你完全破坏了 std::string
成员。
您必须使用复制构造函数来复制 C++ 对象。
按照您现在的方式使用 memcpy
,您将拥有两个完全相同的 std::string
对象。这包括它们可能在内部使用的任何指针。因此,当每个对象的析构函数运行时,它们都试图释放同一个指针。
这就是为什么您需要使用复制构造函数或将一个构造函数分配给另一个构造函数(即使用重写的 operator=
)。它知道这些实现差异并正确处理它们,即它为目标对象分配一个单独的内存缓冲区。
如果要提取 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());
您可以对其他 class 个对象执行类似的步骤。
你得到双重释放错误的真正原因是这样一个事实,而不是为你的变量 a
和 b
创建一个新的字符串对象,你只是复制引用 ( 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;
}