Программа вызывает ошибку _free_dbg(block, _UNKNOWN_BLOCK);

Программа:

class Settlement {
    char* name;
    Land* land;
    int length;
public:
    Settlement() : length(1) {
        name = new char[8];
        strcpy(name, "noname");
        land = new Land[length];
    }
    Settlement(int newLength) : length(newLength) {
        name = new char[8];
        strcpy(name, "S");
        land = new Land[newLength];
    }
Land& operator [](int i) {
        if (i < 0 || i > length) return *land;
        else return *(land + i);
    }


virtual ~Settlement() {
        if(name) delete[] name;
        delete[] land;
    };
void print() {
        cout << "Settlement " << name << " print:" << endl;
        for (int i = 0; i < length; i++)
        {
            land[i].print();
        }
    }

Land - базовый класс, функция print() виртуальная. Main():

Settlement s(3);
s[0] = l1;
s[1] = c1;
s[2] = b1; 
s.print();

l1 - объект класса Land; c1, b1 - объекты классов-наследников land. Программа вызывает ошибку _free_dbg(block, _UNKNOWN_BLOCK); В чем проблема?


Ответы (1 шт):

Автор решения: KoVadim

У Вас в классе есть голые указатели

char* name;
Land* land

а конструктор копирования/оператор присваивания не прописан. И он сгенерирован автоматически. Каждый раз, когда Вы пишите

s[0] = l1;

происходит вызов этих сгенерированных функций. А они просто копируют указатель.

Потом приходит время деструкторов и первый объект разрушает свои вложенные переменные. Вот когда второй пытается разрушить... вот тут и получается Ваша ошибка.

Что делать?

  • Почитать о правиле трех/пяти и написать недостающие функции (конструктор копий и оператор копирования).
  • Либо писать на с++, а не си (правда есть некоторые преподаватели, которым это не нравится). То есть, вместо char* использовать std::string, а вместо Land* land; использовать std::vector<Land> (это самый красивый способ, плюс он поможет избежать чехарды с strcpy и другими штуками с ручным выделением памяти).
  • Либо пойти дальше и использовать умные указатели (unique_ptr/shared_ptr), но в данной ситуации они излишние.
→ Ссылка