#include <iostream>
using namespace std;
class A
{
public:
int a;
A()
{
a=2;
}
~A()
{
a=1;
}
};
int main()
{
A * aa = new A();
delete aa;
if (aa)
cout<< aa->a;
else
cout<<"123";
}
Создаю указатель на экземпляр класса, вызываю конструктор, переменная "a" содержит число 2. Вызываю деструктор (в котором это "a" должно стать равным 1). Сначала ставлю проверку, существует ли указатель на экземпляр класса. Оказалось, что мало того, что он существует после деструктора, так ещё и в "a" лежит число 0. Выходит, в памяти начинают лежать ноли, но она всё ещё занята программой? Как удалить из памяти весь экземпляр класса? Если я заменю ссылку на класс (в данном случае "aa") на отсутствующую, то (по логике) память это не освободит, а лишь не даст мне больше управлять этой памятью по этой ссылке.
[basic.stc]/4
When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values. Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.
(emphasis mine)
После delete aa;
, указатель aa
становится невалидным, и поведение if (aa)
зависит от компилятора.
Что более важно, следующая строка - aa->a
- вызывает неопределенное поведение, из-за доступа через невалидный указатель.
Раз поведение не определено, смысла рассуждать, почему вы видите в консоли 0
или что-то еще - немного.
Сначала ставлю проверку, существует ли указатель на экземпляр класса.
delete
не обнуляет указатель. Так что проверка - не работает.
мало того, что он существует после деструктора
Он не "существует". Объект перестает существовать после вызова на нем деструктора1.
Вот только в языке нет способа проверить, указывает указатель на "существующий" объект, или нет.
так ещё и в "a" лежит число 0
a
- тоже не существует. Читать из него - неопределенное поведение.
Выходит, в памяти начинают лежать ноли, но она всё ещё занята программой? Как удалить из памяти весь экземпляр класса?
Что значит "удалить из памяти"? Память - это набор байт. Вы можете поменять значения байт, в которых находился объект, на какие-то другие, и все. Эти байты нельзя "удалить".
1 Точнее, нетривиального деструктора, но здесь это не важно.
После
delete aa;
значение указателя, хранящегося в переменной aa
не изменяется.
А указывает она на уже освобожденный блок памяти, который может остаться в том же состоянии, быть перезаписанным - в общем, с ним может произойти что угодно (на то и Undefined Behaviour). В любом случае вы не должны к нему обращаться - ни к чему хорошему это привести не может.
Программа имеет неопределенное поведение, так как после удаления объекта класса
delete aa;
значение указателя aa
становится невалидным. То есть указатель не указывает на существующий "живой" объект в программе.
Имейте в виду, что при вызове оператора-функции delete
или delete[]
значение указателя не меняется. так как указатель передается в оператор-функцию по значению, то есть оператор-функция имеет дело с копией значения исходного указателя.
Это означает, что проверка в if-предложении
даст истину
if (aa)
cout<< aa->a
То есть aa
- это не null-указатель
,
Однако обращение к члену уже не существующего объекта
cout<< aa->a
приводит к неопределенному поведению.
Немного увеличим программу, тогда будет понятней:
struct A
{
int a;
A(int k = 2) : a(k) {}
~A() { a=1; }
};
программа:
A * aa = new A();
delete aa;
if (aa)
cout<< aa->a << '\t' << aa << endl;
//
else
cout<<"123" << endl;
A* bb = new A(1245);
// может использоваться память содержащайся в аа а может и нет
cout << bb << '\t' << bb->a << endl;
// теперь хотим использовать и обьявленный b и адрес хранящийся в аа
// размещаем в аа новый обьект
bb = new(aa) A();
//теперь оба указателья содержат один и тот же адрес
cout << aa << '\t' << bb << endl
<< aa->a <<'\t' << bb->a;
Компилятор не знает, что захочет сделать с выделенной памятью программист(или не захочет). Поэтому и не нужно
, как говорится выше проверить, указывает указатель на "существующий" объект, или нет, не только потому что нет в языке такого способа.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Насколько я понимаю, они оба поддерживают наследование, оба могут содержать поля и функции, оба могут содержать конструктор и деструктор,...
Когда пытаюсь выполнить скрипт bimbampy выходит эта ошибка:
Как более правильно описать цикл примерно для следующей схемы кода:
Для генерации случайных чисел использую rand() перед этим иницииирую таймер srand(time(NULL));, но при каждом перезапуске программы числа одинаковые