2016-02-20 4 views
2

Я много слышал о на C++deleteоператор, а также использовали его много до сих пор, но я не знаю, что его реальная работа точно.
То, что я видел в Интернете, было разговором о «освобождении пространства для хранения», но для меня это не имеет смысла для полного понимания проблемы.точная операция удаления оператора

Пожалуйста, ознакомьтесь с фрагментом кода ниже.

int main() 
{ 
    int* p = new int(6); 
    cout << *p << endl; 
    delete p; 
} 

Указатель p имеет свой собственный адрес, так как это переменная (# 1). Указатель p тоже имеет адрес внутри себя, потому что это указатель (# 2). Объект (без имени) содержит значение 6 внутри своего блока памяти, а адрес этого блока памяти совпадает с адресом #2. (Поскольку указатель указывает на этот объект, используя этот адрес.)

Теперь, что произойдет с адресами # 1 и # 2 после выполнения delete;?
Что говорит об этом язык C++?
И каков может быть эффект от разных компиляторов на корпусе?

+1

Это выражение 'delete' ** **, а не вызов оператора' delete' ** **. Последнее является функцией освобождения, которая обычно вызывается выражением 'delete'. После того, как выражение 'delete' вызывает объект-деструктор (или для массива, последовательность таких). –

ответ

3

Теперь, что будет происходить по адресу # 1, # 2 после выполнения удаления; (в коде), пожалуйста?

Указатель p будет иметь неопределенное значение, но он сохранит свой адрес («# 1»).

Объект int объекта *p (с адресом «№ 2») больше не существует. Этот адрес теперь описывает память, которая бесплатна для использования в будущих распределениях.


Что делает язык C++ сказать об этом?

Это:

[C++14: 5.3.5/1]: Оператор удаления выражение уничтожает наиболее производный объект (1.8) или массив, созданный с помощью новой экспрессии. [..]

[C++14: 5.3.5/7]: Если значение операнда удаления-выражения не нулевое значение указателя, а затем:

  • Если вызов распределения для новых-выражений для объекта исключение не было опущено (5.3.4), выражение-удаление должно вызвать функцию освобождения (3.7.4.2). Значение, возвращаемое из вызова выделения нового выражения, передается как первый аргумент функции освобождения.
  • В противном случае выражение удаления не будет вызывать функцию освобождения (3.7.4.2).

А что может быть следствием различных компиляторов по делу?

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

+1

Вы уверены, что «указатель p останется неизменным»? Из других ответов SO я прочитал иначе, например. http://stackoverflow.com/questions/704466/why-doesnt-delete-set-the-pointer-to-null и http://stackoverflow.com/questions/5002055/is-the-pointer-guaranteed-to- preserve-its-value-after-delete-in-c – 4386427

+0

@ 4386427: Хорошая точка; Я имел в виду, что его существование не будет затронуто, и оно никуда не движется, но поскольку ценность может быть чем-то, что вводит в заблуждение. –

+1

@PreferenceBean: Большое спасибо за ваше издание и ответ. Я понял предмет. (Особенно ваша часть ответа). Но я не понял, что означает «самый производный объект» в '[C++ 14: 5.3.5/1]'. И часть '[C++ 14: 5.3.5/7]' была для меня несколько сложной :-) – Franky

2

Что касается

Точная работа удаления оператора

Пример кода в вопросе:

delete p; 

Это deleteвыражение, а не направлять вызов deleteОператор. Оператор является функцией освобождения, которая обычно вызывается выражением delete, после выражения delete вызов вызывает деструктор объекта (или массив, последовательность таких). Вот что происходит:

  1. If p указывает на объект типа класса, то его деструктор называется убирать вещи, например, на свободные ресурсы.

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

Стоит отметить, что для new выражения размещения функции размещения открепления называется, с теми же аргументами Allocator, если строительство не удается при оценке этого new выражения, но позже delete выражение вызывает только обычный стандартный аргумент operator delete , Я не знаю, для чего это необходимо. Но это привело к некоторым ошибкам, в частности, печально известному в MFC, который проявлялся только в отладочных сборках, где была утечка памяти.

3
int main() { 
    int* p;    // p is at address #1 and the value uninitialized. p will 
         // be at address #1 throughout the whole program. 
         // It is only the value of p that can change. 

    p = new int(6);  // The value of p is set to address #2 and your 
         // program now has ownership of sizeof(int) bytes 
         // starting from address #2. The int at address #2 
         // is initialized with the value 6. 
    cout << *p << endl; 

    delete p;   // Your program releases ownership of the memory at 
         // address #2 and you are not allowed to use it anymore. 
         // The value of p is undefined. 

    return 0; 
} 
+0

Неверно, что значение 'p' не определено после' delete' и полностью неразборчиво, когда оно представлено в виде комментариев в коде. – EJP

+1

@EPJ - Из этих ссылок, например. http://stackoverflow.com/questions/5002055/is-the-pointer-guaranteed-to-preserve-its-value-after-delete-in-c и http://stackoverflow.com/questions/704466/why- doesnt-delete-set-the-pointer-to-null, я понял, что значение 'p' не определено после удаления. У вас есть другие источники? – 4386427

2

После delete p, p все еще имеет тот же адрес, как раньше. Объект ушел, поэтому он не имеет адреса. Байты, которые он использовал для занятия, могут использоваться для чего-то другого или могут быть возвращены в ОС; вы не можете смотреть на них, не вызывая неопределенного поведения.

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

Это то, что говорит язык, и компиляторы реализуют его.

Лот Более подробно здесь: http://en.cppreference.com/w/cpp/language/delete

+1

Благодарим вас за ответ. Я думаю, что в (мой отрезанный код) у нас нет утечки, но у нас есть обвисший указатель ('p' после удаления). Вы согласны? Если да, то как спасти его от зависания? Например, как его уничтожить? – Franky

+1

@franky: Если вам необходимо выполнить ручное динамическое размещение, используйте умный указатель, такой как 'std :: unique_ptr' или' std :: shared_ptr', чтобы заботиться о * управлении жизненным циклом *. Не используйте исходные указатели в качестве владельцев, используйте их только как простые ссылки. Не принимайте ошибочную практику обнуления исходных указателей: она дает ложное ощущение безопасности и может помешать усилиям инструментов для обнаружения вещей. –

+0

Спасибо, я бы просто хотел быть знаком с ним. – Franky

Смежные вопросы