Определение правильного формата деструктора в С++

Я столкнулся с этим вопросом:

данный класс А:

class A {
public:
         int size, ** x, *** y;
         A(int _size) {
             size = _size;
             x = new int* [size];
             y = new int** (x);
             for (int i = 0; i < size; i++)
                 x[i] = new int(size);
     }
};

определить правильные деструкторы

есть пять вариантов:

1

~A() {
     for (int i = 0; i < size; i++)
         delete x[i];
     delete [] x;
     delete y;
}

2

~A() {
     delete y;
     for (int i = 0; i < size; i++)
         delete x[i];
     delete[] x;
}

3

~A() {
     delete y;
     delete [] x;
     for (int i = 0; i < size; i++)
         delete x[i];
}

4

~A() {
     delete [] x;
     for (int i = 0; i < size; i++)
         delete x[i];
     delete y;
}

5

~A() {
     for (int i = 0; i < size; i++)
         delete x[i];
     delete y;
     delete [] x;
}

Я думал, что ответ был только в том, что только первый деструктор безопасен, потому что он стирает ресурсы от самых внутренних до самых внешних, тем самым обеспечивая безопасное удаление всех ресурсов и удаление случайных данных.

однако правильный ответ — любой из деструкторов с номерами 1,2,5.

Насколько я понимаю, операнд удаления освобождает память по адресу, на который указывает указатель, поэтому, если мы удалим объект y перед объектом x[], то в x можно будет записать что угодно, и мы не сможем удалить эту информацию, потому что мы не т знаю, что это такое.

Я прав в своем понимании?

Можете ли вы дать мне представление о том, почему деструкторы 2 и 5 жизнеспособны?

а если 2,5 жизнеспособны то почему не 3 и 4?

🤔 А знаете ли вы, что...
C++ обладает возможностью шаблонного программирования, что позволяет создавать обобщенные алгоритмы и структуры данных.


1
58
2

Ответы:

Решено

После того, как вы удалили x, вы больше не можете получить доступ к x[i]. Это исключает 3 и 4.

Порядок удаления y и x, с другой стороны, не имеет значения. Здесь:

 y = new int** (x);

Вы динамически выделяете y и инициализируете его значением x. Это означает x == *y, это единственная связь между ними.

Деструктор, к которому вы действительно должны стремиться, это

~A() {}

Управление памятью — отдельная задача. Достаточно сделать 1 класс. Управление двумя ресурсами уже слишком много для одного класса. Вы можете написать обертки для членов, чтобы правильно управлять памятью, чтобы самому A не нужно было с ней возиться. Однако эта проблема уже решена. Есть умные указатели и контейнеры, вам просто нужно их выбрать и использовать. Я предлагаю сначала взглянуть на std::vector, так как он охватывает большинство вариантов использования.


Вас смущают int **x и int ***y; Обратите внимание, что в вашем примере результаты x и *y одинаковы, но delete y не влияет на x, поэтому вы можете делать это в любом порядке. Важно только delete x[i] до delete[] x;

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