Я столкнулся с этим вопросом:
данный класс А:
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?
*y
содержит значение x
; между указателями y
и x
нет никакой связи. delete
Делать y
первым так же безопасно, как { int x = 1; int* y = new int(x); delete y; }
.
int size, ** x, *** y
- это бесполезное использование указателей... В C++ не используйте new/delete, если вам это не нужно. Посмотрите на std::vector и что вы можете с этим сделать. Где вы изучаете С++? ваш источник кажется устаревшим. (С текущим С++ вам даже не придется сталкиваться с проблемами, которые у вас возникают)
После того, как вы удалили 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.
6) используйте правильные типы для членов, которые инкапсулируют управление памятью и позволяют вам следовать правилу 0, то есть
~A() {};