Проблемы с деструктором

345
25 сентября 2017, 03:32

Main.cpp

#include "Header.h"

int main() {
int arr[][5] = {
    {1,4,6,2,9},
    {2,5,8,2,1},
    {3,2,1,6,9}
};
A* p_a;
//A a(arr[0]);
//p_a = &a;
B* p_b;
//B b(arr[1]);
//p_b = &b;
C* p_c ;
C c(arr[2]);
p_c = &c;
p_c->output(5);
p_a = p_b = p_c;
p_a->output(5);
system("pause");
return 0;
}

Header.h

#pragma once
#include <iostream>
using namespace std;
class A {
protected:
int* data;
public:
void setData(int* d) {
    this->data = d;
}
int* getData() {
    return this->data;
}
A(const A &a) {
    this->data = new int[5];
    this->data = a.data;
}
A() {};
A(int* d) {
    this->data = d;
}
virtual ~A() {
    if (data)
        delete[] this->data;
};
virtual void output(int length) {
    for (int i = 0; i < length; i++) {
        cout << "Index = " << i << "element = " << this->data[i] << endl;
    }
}
};
class B : public A {
public:
B(const B &b) {
    this->data = new int[5];
    this->data = b.data;
}
B() {}
B(int* d) {
    this->data = d;
}
~B() {
    if(this->data)
    delete[] this->data;
}
void output(int length) {
    for (int i = 0; i < length; i++) {
        cout << "Index = " << i << "element = " << this->data[i] << endl;
    }
}
};
class C : public B {
public:
C(const C &c) {
    this->data = new int[5];
    this->data = c.data;
}
C() {}
C(int* d) {
    this->data = d;
}
~C() {
    if(this->data)
    delete[] this->data;
 }
void output(int length) {
    for (int i = 0; i < length; i++) {
        cout << "Index = " << i << "element = " << this->data[i] << endl;
    }
}
}; 

Только недавно начал учить C++, думал что проблема в том, что удаляю уже удаленное, поэтому добавил конструкторы копии, но это не помогло, не могу понять в чем ошибка, пожалуйста подскажите где я ошибаюсь.

Answer 1

Прежде всего нужно понять, кто является собственником памяти, на которую указывает ваш указатель data. Судя по вашему коду, собственником является функция main, в которой расположен массив arr. Данные любого типа в языке C++ могут располагаться в стеке, куче или статической памяти. Все переменные, объявленные в функции, располагаются в стеке, живут там всё время, пока эта функция выполняется, а потом сами уничтожаются. Поэтому вам не нужно удалять их с помощью delete. Если бы вы создавали массив с помощью new, тогда надо было бы удалять.

Есть правило: кто выделил память, тот её и освобождает. В вашем случае память под переменную arr выделяете не вы, а ABI, конкретно - подсистема обслуживания стека. Следовательно, и удалять вы её не должны.

Теперь перейдём к классам A, B, C. Вы передаёте в конструктор этого класса указатель на массив arr. Это делать можно, ничего криминального здесь нет. Но в деструкторе вы пытаетесь эту память освободить, хотя не имеете права: стековую память освобождает ABI. Кроме того, в вашем конструкторе копии творится что-то вообще невообразимое: вы сначала выделяете новую память и записываете указатель на неё в переменную data, и тут же его отбрасываете, перезаписывая другим значением. Это утечка памяти. Хотя, открою вам секрет: конструктор копии в вашем коде нигде не используется.

В связи с вышеизложенным, советую вам определиться, кто будет являться собственником памяти и кто будет её удалять. Исходя из вашего решения нужно будет исправлять код.

Answer 2

Как минимум, вы сами себе организуете утечку памяти - например,

this->data = new int[5];
this->data = c.data;

Во-вторых, вы очень вольно распоряжаетесь указателями, передавая их налево и направо (например, при копировании вы просто передаете указатель), а потом в деструкторе их удаляете. Что приводит к многократному удалению - уже ужас.

Но вы же еще и передаете указатели не на динамически выделенную память, а потом ее пытаетесь удалять. Понятно, что программа жить не хочет...

В конструкторе по умолчанию стоит инициализировать указатель нулевым значением - иначе потом может быть попытка удаления не пойми чего.

Чисто по стилю - зачем вы везде таскаете эти this->? В большинстве случаев они просто ничего не дают... И еще - проверять указатель на ненулевое значение не нужно - это делает сам оператор delete.

READ ALSO
Разные обьекты синглетона

Разные обьекты синглетона

Есть два класса: А и BA это Sigleton, B простой класс(для примера)

373
Системы сборки проектов C/C++

Системы сборки проектов C/C++

Думаю над тем как обустроить быт разработки на C/C++ под линуксНа CLion денег жалко

394
Вопрос по задаче (C4) в ЕГЭ по информатике

Вопрос по задаче (C4) в ЕГЭ по информатике

Считается ли мое решение эффективным по времени? Понимаю, что по памяти оно неэффективно, тк используются структуры данных\контейнеры, а вот...

304
gets_s() в цикле съедает первый символ в строке

gets_s() в цикле съедает первый символ в строке

Всем доброго времени сутокВот такой вопрос:

320