Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: Указатели и delete  (Прочитано 37971 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Mfcer__
Команда клуба

ru
Offline Offline

« : 23-11-2003 19:22 » 

Допустим есть объявлен указатель, но память не выделена:
SOMESTRUCT *data;
перед выделением памяти нужно сделать проверку, может память уже выделена? Типа
if(память выделена==ДА)
delete data;
data = new SOMESTRUCT[NUM];
Как написать условие?
Записан
Alf
Гость
« Ответ #1 : 23-11-2003 19:36 » 

При выделении памяти под динамически создаваемый объект в "куче" резервируется соответствующий объем памяти, а затем указателю присваивается ссылка на него.
Неинициализированный указатель имеет значение "пустой" ссылки - NULL.
В известных мне реализациях NULL == 0, поэтому обычно срабатывает вариант
Код:
SOMESTRUCT *data;
...
if (data) { // память не выделена
На мой взгляд, не лучший вариант, т.к. тождество NULL == 0 стандартом языка не оговорено, и в принципе можно наткнуться на реализацию, в которой он не сработает.
Вот переносимый вариант:
Код:
SOMESTRUCT *data;
...
if (NULL == data) { // память не выделена
« Последнее редактирование: 22-11-2007 14:59 от Алексей1153++ » Записан
Sashok
Молодой специалист

us
Offline Offline
Пол: Мужской

« Ответ #2 : 23-11-2003 19:47 » 

Mfcer__, при работе с обычным пойнтером, как в С, я помещаю NULL в пойнтер при освобождении памяти. Если ты этого не сделал, никак не определить, адрес сидящий в пойнтере указывает на все еще отведенную память или на уже освобожденную, поскольку оператор delete не обнуляет пойнтер. Если придерживаться правила обнуления, условие становится тривиальным:
Код:
if(data != NULL)
{
  delete data;
  data=NULL;
}
« Последнее редактирование: 22-11-2007 15:00 от Алексей1153++ » Записан

Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
Sashok
Молодой специалист

us
Offline Offline
Пол: Мужской

« Ответ #3 : 23-11-2003 19:49 » new

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

Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
Alf
Гость
« Ответ #4 : 23-11-2003 20:14 » 

Цитата: Sashok
Alf, ты не учитываешь вариант, когда пойнтер уже один раз использовался и был освобожден, а теперь отводится снова.

Строго говоря, да. Только данное предостережение относится исключительно к трюкачам, которые, освободив область памяти, оставляют указатели на нее в висячем состоянии в надежде, что помнят об этом и не попытаются их разыменовать. Возможно, что и правда будут помнить целую неделю после написания кода. К сожалению, сегодняшний вариант языка позволяет делать подобные фокусы (еще один низкий поклон создателям C#), но вряд ли они относятся к хорошей манере программирования.
Профессионал вряд ли будет экономить пару-тройку наносекунд на обнулении ненужного более указателя, создавая потенциально неустойчивый код. Да и заданный вопрос имеет однозначный ответ только при данной технике работы с указателями.
Записан
Mfcer__
Команда клуба

ru
Offline Offline

« Ответ #5 : 23-11-2003 21:15 » 

Цитата

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

А как это проверять? Можн пример плз.  :?
Записан
Alf
Гость
« Ответ #6 : 23-11-2003 21:34 » 

Цитата: Mfcer__

А как это проверять? Можн пример плз.  :?

Если взять за правило обнулять указатели после каждого освобождения - то так, как я показал.
Если обращаться с ними как попало - то никак. И заодно приготовиться получить букет малоприятных, трудновоспроизводимых и крайне неудобных в отладке ошибок.
Записан
grozny
Гость
« Ответ #7 : 24-11-2003 03:26 » 

Отлично

есть такие полезные понятия, как смарт-пойнтеры в С++.

Но для начала - да, держите пустой указатель нулём - будет вам щастье, это правильный стиль. За систематическое необнуление освобождённых указателей  8) могут и с работы пнуть.  Я шокирован!

в простых случаях я пишу примерно так:

SomeClass* p=0;
...
bool Container::create()
{
   bool rc=false;
   if(!p){p = new SomeClass; rc = (p!=0);}
   return rc;
}
...
bool Container::destroy()
{
   bool rc=false;
   if(p) {delete p; p=0; rc=true;}
   return rc;
}
А кому-то NULL нравится. Замечу, что NULL - понятие вовсе не компиляторное. Определяется в stdlib.h string.h, stddef.h и куче других мест в заголовках ран-тайма:

Код:
/* Define NULL pointer value */

#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else  /* __cplusplus */
#define NULL    ((void *)0)
#endif  /* __cplusplus */
#endif  /* NULL */

Обратите внимание, что для С++ NULL не типизирован явно, так что можно спокойно присваивать и сравнивать с любым типом.
« Последнее редактирование: 22-11-2007 15:02 от Алексей1153++ » Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #8 : 24-11-2003 08:44 » 

Полностью согласен с Грозным, я делаю тоже так, просто два правила:
1. Инициаллизируй указатель с NULL; (в принципе правило не только для указателей - всё надо инициаллизировать!) int *p = NULL;

тогда значение отличное от нуля в указателе будет только после new. И проверять ничего не надо.

2. после delete сразу указатель обнулять. delete p; p = NULL;

кстати, Sashok, проверка типа

if(data != NULL) delete data;

не нужна, ты можешь delete вызывать и с нулевым указателем, даже если один раз delete был вызван, то указатель от этого не обнуляется те он не NULL поэтому
при повторном вызове delete произойдёт удаление уже удалённего блока - ERROR.

Выход - правило 2. Ага
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Mfcer__
Команда клуба

ru
Offline Offline

« Ответ #9 : 24-11-2003 09:47 » 

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

de
Offline Offline
Пол: Мужской

« Ответ #10 : 24-11-2003 10:05 » 

smart pointers - если это имеется ввиду. Обычно такие классы в которых в качестве данных хранятся указатели на объекты других классов, что позволяет дополнить их механизмом управления  этими классами. Например, механизмом удаления объектов внутри "умного" класса.

Про использовать - сорри - никогда не использовал.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #11 : 24-11-2003 10:58 » 

Мой опыт в таких делах говорит одно.
В любой реализации, чему бы не был равен NULL есть возможность перегрузить функцию delete.

Для самой простейшей вещи я делаю обычно следующее:

destroy_point(void *);

Обычно в проекте любом (кроме очень маленьких) я держу файл common.h в котором такие функции пишу.


Код:

destroy_point(void * p)
{
     if (p!=NULL) delete p;
     p=NULL;
}



При этом я не пользуюсь напрямую функцией delete - и это гарантирует мне, что если мой указатель свободен он всегда NULL;
« Последнее редактирование: 22-11-2007 15:03 от Алексей1153++ » Записан

А птичку нашу прошу не обижать!!!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #12 : 24-11-2003 11:12 » 

Гром, а зачем проверка?

if (p!=NULL) delete p;

делай сразу delete p;
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #13 : 24-11-2003 12:37 » 

Джон, а если ошибка в программе с двойным освобождением?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #14 : 24-11-2003 12:57 » 

Не понял, что значит с "двойным освобождением"?

Я просто про то, что этот опрос ничего не даёт.
Скажем так если р инициаллизирована и объект уже был удалён, то это не спасает. А если р=NULL; то можно смело вызывать delete p; беды не будет
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #15 : 24-11-2003 13:30 » 

Двойное освобождение - это неоднократный вызов освобождения блока памяти. Например, если ты поставишь тот же delete для одного и того же указателя в нескольких местах, а сработает не один, а два.
Конечно на нулевой указатель выпадет ошибка - о том и горорит народ - если бы был не 0, то могло ошибки не выдать, но чужие данные попортить.

Зачем нужен if(p) delete p ?
Например, указатель - часть некой структуры (или класса) и, по условию алгоритма, необязательно должен указывать на выделеный блок. При вызове ф-ии удаления структуры, надо, прежде чем делатть delete, проверить, занималась ли память для этого указателя.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #16 : 24-11-2003 13:50 » 

Наверно я неправильно говорю. Вот что я имею ввиду:

int *p = NULL;
p = new int(3);
delete p;
p=NULL;

где-нить

delete p;  вместо if(p) delete p; !!!!!


Цитата: RXL
Двойное освобождение - это неоднократный вызов освобождения блока памяти. Например, если ты поставишь тот же delete для одного и того же указателя в нескольких местах, а сработает не один, а два.
Конечно на нулевой указатель выпадет ошибка - о том и горорит народ - если бы был не 0, то могло ошибки не выдать, но чужие данные попортить.


В том то и дело что проверка идёт проще говоря - какое значение стоит в р 0 или не 0. В данном случае после первого delete в р остаётся прежнее значение. И проверка if(p) сработает как true. А если р будет один раз обнулён то не имеет смысла проверять его на нуль.

Цитата

Зачем нужен if(p) delete p ?
Например, указатель - часть некой структуры (или класса) и, по условию алгоритма, необязательно должен указывать на выделеный блок. При вызове ф-ии удаления структуры, надо, прежде чем делатть delete, проверить, занималась ли память для этого указателя.


То то и оно, что if(p) не отвечает на этот вопрос однозначно. Оно только говорит, что в р лежит какое-то значение и ты не можешь без доп. сведений разрешать удаление этого блока. Проверка if(p) delete p; в данном случае ничего не даст. Если р - NULL, то delete сработает, а если р не NULL, то будет ошибка. "С" или "Без" if.

Ну наверное так будет понятнее:

int *p = NULL;
delete p;
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Sashok
Молодой специалист

us
Offline Offline
Пол: Мужской

« Ответ #17 : 24-11-2003 22:42 » 

Ну, ребята, вы и туману напустили...
Цитата: Джон
кстати, Sashok, проверка типа

if(data != NULL) delete data;

не нужна, ты можешь delete вызывать и с нулевым указателем, даже если один раз delete был вызван, то указатель от этого не обнуляется те он не NULL поэтому
при повторном вызове delete произойдёт удаление уже удалённего блока - ERROR.
Ты совершенно правильно обосновал, почему она как раз нужна: чтобы не было повторного удаления блока.

А в коде, который я написал, я почему-то не включил ( :oops: ) еще одну строчку, хотя в тексте в явном виде упомянул: обнуление пойнтера.

На настоящий момент сообщение отредактировано!

Насчет смарт-пойнтеров: именно для того, чтобы сразу не морочить человеку голову смарт-пойнтерами я и начал ответ с фразы:
Цитата
при работе с обычным пойнтером, как в С...


Если же говорить о смарт-пойнтерах, то прежде надо выяснить, знаком ли человек с перегрузкой операторов. ИМХО.
Записан

Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #18 : 24-11-2003 23:15 » 

Джон, я как раз и говорю, что я пишу вместо обычного delete функциюшку в которой делаю проверку - и если не 0 то тогда делетю его, а если ошибка и я уже его делетил - то не делаю этого.
НО!!!
Самое главное - вызывая только эту функцию у меня все мои указатели будут равны NULL всегда после удаления...
Просто не всегда я работаю над проектом один, отсюда проблема не нулевого и уже убитого указателя. Но это невозможно обойти...
Записан

А птичку нашу прошу не обижать!!!
SAA
Гость
« Ответ #19 : 25-11-2003 06:33 » 

А помоему, Джон прав. Зачем вам проверка указателя?
Применим delete без проверки в трех случаях:
Код:
1. указатель валидный          -> OK
2. указатель = 0              -> OK
3. указатель "убитый", но != 0 -> Error!

Если мы используем проверку перед удалением, результаты будут такими же как и без проверки.

А вместо функции можно использовать макрос.
#define DELETE(p) delete(p);(p)=0;
Записан
Serega
Гость
« Ответ #20 : 25-11-2003 07:10 » 

Вот и дожили до макросов Отлично
Пора переходить к умным указателям :arrow:
Начнем с простенького
Код:
template <class PtrType>
class MyPtr
{
PtrType* ptr;
public:
MyPtr(PtrType* p) : ptr(p) {}
~MyPtr() { delete ptr; }
PtrType* operator->() { return ptr; }
};
« Последнее редактирование: 22-11-2007 15:06 от Алексей1153++ » Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #21 : 25-11-2003 09:06 » 

Я всё понял!! Формулирую так: "Их бин дубин - Я есть плох руски говорит".  Ага

SAA,  спасибо - кажется ты меня понял, - это я и хотел сказать. Что без проверки это работает точно так-же.

Serega,  если время будет - набросай пожалуйста статейку по smart pointers - я их только "теоретически" проходил. Много текста писать не надо - лучше куски кода (можно псевдо) и какая выгода от их использования.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
SAA
Гость
« Ответ #22 : 25-11-2003 16:29 » 

2 Джон
Цитата
SAA, спасибо - кажется ты меня понял, - это я и хотел сказать. Что без проверки это работает точно так-же.

Да это вам всем спасибо. Улыбаюсь А то я ни сном, ни духом про обнуление указателей. Мотаю на ус. Отлично

Про умные указатели очень хорошо написано в книге Jeff Alger "C++ for real programmers". По крайней мере, даже я, чайник, понял их суть.

Serega  - даешь статью по smart-poinetrs! А макросы кое-где даже очень ничего. Ага
Записан
Sashok
Молодой специалист

us
Offline Offline
Пол: Мужской

« Ответ #23 : 25-11-2003 16:31 » 

Цитата: SAA
А помоему, Джон прав. Зачем вам проверка указателя?
Применим delete без проверки в трех случаях:
Код:
1. указатель валидный          -> OK
2. указатель = 0              -> OK
3. указатель "убитый", но != 0 -> Error!

Если мы используем проверку перед удалением, результаты будут такими же как и без проверки.
SAA, Джон, да вы что - в трех соснах заблудились? Как раз вариант 3. и недопустим, это же повторное освобождение памяти! Тот самый Error!.

А если при каждом освобождении указатель обнулять, то как раз третьего варианта не будет. Надеюсь, что в полезности обнулять указатель немедленно после освобождения я вас убедил.

Теперь о проверке. Да, delete к нулю применять можно. Но есть еще один момент: если программа добралась до кода, где не известно, указатель действительный, или уже освобожденный, она ничего не может с ним делать без проверки, кроме освобождения, да и освобождение допустимо только, если в указателе ноль. С точки зрения вероятности внести ошибку, на мой взгляд, хороший стиль заключается в том, чтобы везде в коде, где не известно истинное состояние указателя проверять его на ноль, а при освобождении - всегда обнулять.
Записан

Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
Mfcer__
Команда клуба

ru
Offline Offline

« Ответ #24 : 25-11-2003 19:49 » 

Цитата

Serega - даешь статью по smart-poinetrs!

Поддерживаю однозначно - НА БИС !!!  Отлично   Ага
Записан
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #25 : 25-11-2003 22:30 » 

Цитата

Serega - даешь статью по smart-poinetrs!

Суппорт.
Записан

А птичку нашу прошу не обижать!!!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #26 : 26-11-2003 11:56 » 

Sashok,  Ну хорошо, сделаем подругому.
Объясни в чём разница выполнения этого кода:
Код:
if(p!=NULL) delete p;
p=NULL;
от этого:
Код:
delete p;
p=NULL;

Что будет по-другому? Ага

Цитата: Sashok
А если при каждом освобождении указатель обнулять, то как раз третьего варианта не будет. Надеюсь, что в полезности обнулять указатель немедленно после освобождения я вас убедил.

Читай, что я в первом топике написал.  Ага Правило 2
« Последнее редактирование: 22-11-2007 15:11 от Алексей1153++ » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Diletant
Помогающий

de
Offline Offline

« Ответ #27 : 26-11-2003 12:49 » 

"Слушал я вас слушал, долго и внимательно" (С) Кто сказал, что неинициализированный указатель равен 0? В VC не равен, просто по определению. Даже в дебаг версии. А про релиз я даже не говорю.
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #28 : 26-11-2003 12:54 » 

И ещё одно, до кучи. Теперь уже моё личное мнение про стили Ага

Я всегда считал такой код НЕ хорошим стилем

Код:
#define BIT2 4

if(dwFlag&BIT2!=BIT2) dwFlag|=BIT2;
я делаю сразу так:
Код:
dwFlag|=BIT2;

По-моему это тоже самое.
« Последнее редактирование: 22-11-2007 15:13 от Алексей1153++ » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #29 : 26-11-2003 12:58 » 

Цитата: Diletant
Кто сказал, что неинициализированный указатель равен 0?


Кто такое говорил? Я шокирован!
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines