Почему ниже части кода не отказывает, хотя я удалил объект?

class object
{
  public:
    void check()
    {
      std::cout<<"I am doing ok..."<<std::endl;
    }
};

int main()
{
  object *p = new object;
  p->check();
  delete p;
  p->check();
  delete p;
  p->check();
}

Править: Гуру, я смущен многими операторами, "это может отказать, или не может".. почему не там стандарт для высказывания, это, как мы имеем дело с блоком памяти, которая удалена с помощью 'оператора delete'..? Какие-либо исходные данные?

7
задан stefanB 17 June 2009 в 11:30
поделиться

10 ответов

Потому что то, что на самом деле выглядит после того, как компилятор добился своего, выглядит примерно так:

object::check( object* this )
{
     // do stuff without using this
}

int main()
{        
     object *p = new object;
     object::check( p );
     delete p;
     object::check( p );
     delete p;
     object::check( p );
 }

Поскольку вы не касаетесь «этого», вы фактически не получаете доступа к плохим память.

Хотя двойное удаление p может привести к сбою:

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.2

10
ответ дан 6 December 2019 в 05:08
поделиться

1) Зависит от компилятора, в Mac OS с gcc 4.0.1:

g++ -Wall -g -c main.cpp -o main.o
g++ -o x main.o 
./x
I am doing ok ...
I am doing ok ...
x(5857) malloc: *** error for object 0x100150: double free
*** set a breakpoint in malloc_error_break to debug
I am doing ok ...

Двойное освобождение вызывает проблемы.

2) Обычно удаление указателя, который уже был удален, не определено , вы всегда должны устанавливать указатель на 0 после удаления, вызов delete для указателя со значением 0.

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

1
ответ дан 6 December 2019 в 05:08
поделиться

delete не устанавливает p равным нулю, поэтому он по-прежнему указывает на ячейку памяти. Это зависит от реализации new / delete, но обычно при удалении помечается только эта часть памяти как доступная для любых новых выделений.

Это похоже на удаление файла с жесткого диска. Файловая система просто отмечает эту область как доступную. Данные файла существуют и могут быть восстановлены до тех пор, пока вы не будете выполнять новые записи.

1
ответ дан 6 December 2019 в 05:08
поделиться

Поскольку функция ничего не делает с данными члена объекта или указателем this .

Это похоже на вызов функции

void check(object *self)
{
  std::cout<<"I am doing ok..."<<std::endl;
}

с недопустимым указателем в качестве self аргумент.

Однако есть двойное удаление, которое может привести к сбою в некоторых средах.

7
ответ дан 6 December 2019 в 05:08
поделиться

Удаление только освобождает память и делает ее доступной обратно в кучу.

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

Совет по программированию, который я использую для уменьшения количества ошибок программирования, заключается в том, чтобы после удаления установить указатель на NULL. Таким образом, вы знаете, что не случайно используете указатель после его удаления.

7
ответ дан 6 December 2019 в 05:08
поделиться

Вы можете сделать то же самое с указателями nil, если вы никогда не получите доступ к состоянию экземпляра класса:

class object
{
  public:
    void check()
    {
      std::cout<<"I am doing ok..."<<std::endl;
    }
};

int main()
{
  object *p = 0;
  p->check();
}
5
ответ дан 6 December 2019 в 05:08
поделиться

Это еще смешнее. Это прекрасно компилируется и работает:

#include <iostream>
using namespace std;
class object {
    public:
      void check() {
          cout << "I am doing ok..." << endl;
      }
};

int main() {
   object *p = (object*)0;
   p->check();
   return 0;
}

В оболочке:

$ g++ -o t t.cc
$ ./t
I am doing ok...
$

:) Вам действительно не нужно иметь объект для вызова этого метода! ура, ч

5
ответ дан 6 December 2019 в 05:08
поделиться

Даже если при вызове метода использовался указатель this, сбой не гарантировался. Указатель p при удалении не обнуляется, поэтому по-прежнему указывает на тот же адрес в памяти. В зависимости от реализации new / delete и диспетчера кучи, эта память может даже не использоваться повторно, поэтому использование p может продолжать работать, даже если память была освобождена.

2
ответ дан 6 December 2019 в 05:08
поделиться

Чтобы немного дополнить сказанное другими, попробуйте использовать переменную-член вашего класса внутри метода check (), а затем посмотрите, что произойдет.

Вызов функции в случае классов выполняется похож на обычный вызов функции, за исключением одной небольшой разницы. Аргументы помещаются в стек в обоих случаях, но в случае вызова функции объекта this помещается в стек в качестве первого аргумента. Это 'this' используется внутри функции для доступа к переменным-членам. Поскольку вы не обращаетесь ни к каким переменным-членам, он работает. И да, это может работать, даже если вы обращаетесь к переменным-членам, но вы получите неожиданное поведение, потому что компилятор может использовать память, выделенную для p. Как только компилятор использует эту память, вы начнете получать сбои. Например,

0
ответ дан 6 December 2019 в 05:08
поделиться

Я думаю, это зависит от среды (платформы / компилятора) ...
По крайней мере, это дает неожиданное поведение. Думаю, вам повезло, что в вашем случае он не вылетает; -)

0
ответ дан 6 December 2019 в 05:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: