ошибка double free или corruption при копировании объекта с помощью 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)

оказывается, код может распечатать результат. Но как я могу исправить эту ошибку?

3 ответов


С помощью 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());

выполните аналогичные действия для других объектов класса.


нельзя memcpy() структура без стручка, как test. Вы полностью разрушаете std::string член.

вы должны используйте конструктор копирования для копирования объектов C++.


фактическая причина, по которой вы получаете двойную бесплатную ошибку, связана с тем, что вместо создания нового строкового объекта для ваших переменных a и b, вы просто копируете ссылку (a 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;
}