Чому не видалити встановити вказівник на NULL?


127

Мені завжди було цікаво, чому автоматичне встановлення покажчика на NULL після видалення не є частиною стандарту. Якщо це вирішиться, тоді багато збоїв через недійсний покажчик не відбудуться. Але сказавши, що я можу придумати кілька причин, чому стандарт обмежив би це:

  1. Продуктивність:

    Додаткова інструкція може уповільнити deleteпродуктивність.

  2. Можливо, через constпокажчики.

    Тоді знову стандартний міг би щось зробити для цього особливого випадку.

Хтось знає точні причини, щоб цього не допустити?

Відповіді:


150

Сам Струструп відповідає. Уривок:

C ++ явно дозволяє реалізації delete видалити нульовий операнд lvalue, і я сподівався, що реалізація зробить це, але ця ідея, схоже, не стала популярною серед реалізаторів.

Але головне питання, яке він виникає, полягає в тому, що аргумент delete не повинен бути значенням.


Я думаю, що це могло б використати ще одне пояснення. Я навіть не впевнений, що він говорить ... Я вважаю, що мені доведеться повернутися в більш пізній час, коли я можу присвятити кілька годин дослідженню цього, поки не зрозумію. Або ви можете пояснити відповідь, щоб допомогти нам швидше зрозуміти.
Габріель

63

По-перше, для встановлення нуля знадобиться змінна, що зберігається в пам'яті. Це правда, що у вас зазвичай є вказівник на змінну, але іноді ви можете видалити об'єкт за щойно обчисленою адресою. Це було б неможливо з "нульовим" видаленням.

Потім настає вистава. Можливо, ви написали код таким чином, що покажчик вийде за межі одразу після завершення видалення . Заповнення його нулем - це лише марна трата часу. А C ++ - це мова з ідеологією "не потрібна? Тоді не потрібно платити за неї".

Якщо вам потрібна безпека, до ваших послуг широкий спектр розумних покажчиків, або ви можете написати свої - кращі та розумніші.


4
Добре бачити wrt розрахунок адреси, навіть якщо це щось, що ви не бачите часто
Snemarch

ви говорите про місце розташування нового, коли ви говорите, що іноді ви можете видалити об'єкт за щойно обчисленою адресою. ???
Деструктор

@PravasiMeet Ні, я маю на увазі щось на кшталтdelete (ptr + i)
shartooth

39

Ви можете мати кілька покажчиків, що вказують на цю пам'ять. Це створило б помилкове почуття безпеки, якби вказаний вами покажчик для видалення встановив нуль, але всі інші вказівники цього не зробили. Вказівник - це не що інше, як адреса, число. Можливо, це також буде int з операцією з відміни. Думаю, вам доведеться також сканувати кожен покажчик, щоб знайти ті, що посилаються на ту саму пам’ять, яку ви тільки що видалили, а також обнулити їх. Було б обчислювально інтенсивно сканувати всі покажчики на цю адресу і обнуляти їх, оскільки мова не призначена для цього. (Хоча деякі інші мови структурують свої посилання по-різному для досягнення подібної мети.)


19

Вказівник може бути збережений у більш ніж одній змінній, якщо встановити одну з них на NULL, все ще залишатиметься недійсними покажчики в інших змінних. Таким чином, ви насправді не дуже заробляєте, ви, швидше за все, створюєте помилкове почуття безпеки.

Крім цього, ви можете створити власну функцію, яка виконує те, що ви хочете:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}

12

Тому що насправді немає ніякої необхідності і тому, що це вимагатиме видалення, беручи вказівник на покажчик, а не просто вказівник.


правда, але це призведе до того ж накладних витрат
снімарх

7

deleteзастосовується здебільшого в деструкторах, в цьому випадку встановлення члена на NULL безглуздо. Кілька рядків пізніше, при закритті }, члена вже немає. У операторах присвоєння видалення, як правило, супроводжується призначенням у будь-якому випадку.

Крім того, він зробить такий код незаконним:

T* const foo = new T;
delete foo;

6

Ось ще одна причина; припустимо, delete видає свій аргумент NULL:

int *foo = new int;
int *bar = foo;
delete foo;

Чи слід встановити смугу NULL? Чи можете ви це узагальнити?


5

Якщо у вас є масив покажчиків, і ваше друге дію полягає в тому, щоб видалити порожній масив, тоді немає значення, коли кожне значення буде встановлено на нуль, коли пам'ять збирається звільнитися. Якщо ви хочете, щоб це було нульовим .. напишіть це null :)


4

C ++ дозволяє визначити власного оператора new і видалити, щоб, наприклад, вони використовували ваш власний розподільник пулу. Якщо ви це зробите, то ви можете використовувати нові та видалити з речами, які не є суто адресами, але кажуть індекси у масиві пулу. У цьому контексті значення NULL (0) може мати юридичне значення (стосується першого пункту в пулі).
Тож автоматичне видалення встановленого NULL до його аргументу не завжди має значення - встановити значення на недійсне значення. Недійсне значення не завжди може бути NULL.


4

Філософія C ++ - це "платити за неї, лише якщо ти її використовуєш". Я думаю, це може відповісти на ваше запитання.

Також іноді ви можете мати власну купу, яка відновить видалену пам'ять .. або іноді вказівник, яким не володіє жодна змінна. Або вказівник, що зберігається в декількох змінних - можливо нуль лише однієї з них.
Як бачите, у нього є багато проблем та можливих проблем.


3

Встановлення вказівника на NULL автоматично не вирішить більшість проблем із поганим використанням вказівника. Єдиний збій, якого б уникнути, це якщо спробувати видалити його двічі. Що робити, якщо ви викликаєте функцію-член на такому вказівнику? Вона все одно буде завершена (якщо припустити, що вона отримує доступ до змінних членів). C ++ не обмежує вас викликати будь-яку функцію за вказівниками NULL, а також не робити це з точки зору продуктивності.


-1

Я бачу людей, які дають дивні відповіді на це питання.

ptr = NULL; Як таке просте твердження може спричинити затримку продуктивності?

Інша відповідь говорить про те, що у нас може бути кілька покажчиків, що вказують на одне місце пам’яті. Звичайно, ми можемо. У цьому випадку операція видалення на одному вказівнику зробить лише цей покажчик NULL (якщо видалення створює покажчик NULL), а інший покажчик буде не-NULL і вказуватиме на вільне місце пам'яті.

Рішенням цього повинно було стати те, що користувач повинен видалити всі вказівники, що вказують на те саме місце. Всередині слід перевірити, чи пам'ять вже звільнена, ніж не вільна. Зробіть лише покажчик NULL.

Stroustrup міг сконструювати видалення для роботи таким чином. Він думав, що програмісти подбають про це. Тому він ігнорував.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.