Удаление C ++ указателей на объект - PullRequest
1 голос
/ 28 октября 2010

Я думал, что команда удаления освободит память, которую я выделил. Может кто-нибудь объяснить, почему после удаления память все еще используется?

class Test
{
public:
    int time;
};

int main()
{
    Test *e;

    e = new Test;

    e->time = 1;
    cout << e->time << endl;

    delete e;

    e->time = 2;
    cout << e->time << endl;

    return(0);
}

Я ожидал ошибки сегмента после e-> time = 2;

Спасибо!

Ответы [ 9 ]

9 голосов
/ 28 октября 2010

Я ожидал ошибки сегмента после e-> time = 2;

Вы не должны «ожидать», что что-то случится; Вы вызываете неопределенное поведение, которое по определению, ну, в общем, не определено. Это означает, что вы больше не можете делать какие-либо разумные ожидания относительно состояния вашей программы.

2 голосов
/ 28 октября 2010

Неопределенное поведение - это просто неопределенное поведение.Это может даже работать, если это так радует.

1 голос
/ 28 октября 2010

Когда вы «удаляете» память, вы в основном возвращаете выделенную память обратно в кучу. Это просто означает, что структура данных, используемая для организации памяти кучи, обновляется, чтобы указать, что память теперь доступна для использования. Это не очищается или что-то в этом роде. Вы обращаетесь к памяти, которая все еще существует, но в данный момент принадлежит к операционной системе. Это неопределенное поведение.

EDIT:

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

0 голосов
/ 28 октября 2010

Причина, по которой ваши тесты не ломаются - это комбинация удачи и тот факт, что у вас очень простая и очень короткая рутина. Вы обращаетесь к памяти, все еще находящейся в пространстве вашего процесса, и у вас так мало инструкций, что процедура, вероятно, выполняется за один раз.

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

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

Поскольку он снова используется очень быстро, оставленные вами значения (вероятно, будут) все еще там, и вряд ли будут использоваться другим процессом.

0 голосов
/ 28 октября 2010

Как уже говорили другие, то, что вы сделали, неверно, но вы не можете ожидать какого-либо конкретного поведения.

В большинстве современных систем, вероятно, происходит то, что память выделяется для eнаходится на странице памяти, отображенной как допустимая для вашей программы, и тот факт, что у вас есть delete d e, не отменяет это отображение.

Таким образом, вы все еще получаете доступ к памяти, которую ваше приложение имеет разрешение на использование из ОС.Таким образом, нет ошибки сегментации. возможно возможно, однако, если между delete e и доступом к этой памяти произойдет достаточно вещей, страница будет переназначена. Тогда вы получаете ошибку сегмента.

0 голосов
/ 28 октября 2010

запустить его под Valgrind. это скажет вам, что вы сделали плохо

0 голосов
/ 28 октября 2010

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

Test *e;
e->time = 2;

также компилируется и не будет работать. Минимизируйте этот тип путаницы так:

{
  boost::scoped_ptr<Test> e(new Test);

  e->time = 1;
  cout << e->time << endl;

  e->time = 2;
  cout << e->time << endl;
}

Нет new/delete необходимо, просто заключив в скобки, чтобы определить область, и соответствующий умный указатель.

0 голосов
/ 28 октября 2010

Разыменование указателя на удаленный объект не определено. Возможно, память для этого объекта еще не была перезаписана, поэтому ваш объект все еще там (если он вообще работает).

0 голосов
/ 28 октября 2010

Доступ к удаленному объекту - неопределенное поведение.Все может случиться

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...