|
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
Молодой специалист
Offline
Пол:
|
|
« Ответ #2 : 23-11-2003 19:47 » |
|
Mfcer__, при работе с обычным пойнтером, как в С, я помещаю NULL в пойнтер при освобождении памяти. Если ты этого не сделал, никак не определить, адрес сидящий в пойнтере указывает на все еще отведенную память или на уже освобожденную, поскольку оператор delete не обнуляет пойнтер. Если придерживаться правила обнуления, условие становится тривиальным: if(data != NULL) { delete data; data=NULL; }
|
|
« Последнее редактирование: 22-11-2007 15:00 от Алексей1153++ »
|
Записан
|
Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
|
|
|
Sashok
Молодой специалист
Offline
Пол:
|
|
« Ответ #3 : 23-11-2003 19:49 » |
|
Alf, ты не учитываешь вариант, когда пойнтер уже один раз использовался и был освобожден, а теперь отводится снова.
|
|
|
Записан
|
Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
|
|
|
Alf
Гость
|
|
« Ответ #4 : 23-11-2003 20:14 » |
|
Alf, ты не учитываешь вариант, когда пойнтер уже один раз использовался и был освобожден, а теперь отводится снова. Строго говоря, да. Только данное предостережение относится исключительно к трюкачам, которые, освободив область памяти, оставляют указатели на нее в висячем состоянии в надежде, что помнят об этом и не попытаются их разыменовать. Возможно, что и правда будут помнить целую неделю после написания кода. К сожалению, сегодняшний вариант языка позволяет делать подобные фокусы (еще один низкий поклон создателям C#), но вряд ли они относятся к хорошей манере программирования. Профессионал вряд ли будет экономить пару-тройку наносекунд на обнулении ненужного более указателя, создавая потенциально неустойчивый код. Да и заданный вопрос имеет однозначный ответ только при данной технике работы с указателями.
|
|
|
Записан
|
|
|
|
Mfcer__
Команда клуба
Offline
|
|
« Ответ #5 : 23-11-2003 21:15 » |
|
Alf, ты не учитываешь вариант, когда пойнтер уже один раз использовался и был освобожден, а теперь отводится снова.
А как это проверять? Можн пример плз. :?
|
|
|
Записан
|
|
|
|
Alf
Гость
|
|
« Ответ #6 : 23-11-2003 21:34 » |
|
А как это проверять? Можн пример плз. :?
Если взять за правило обнулять указатели после каждого освобождения - то так, как я показал. Если обращаться с ними как попало - то никак. И заодно приготовиться получить букет малоприятных, трудновоспроизводимых и крайне неудобных в отладке ошибок.
|
|
|
Записан
|
|
|
|
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++ »
|
Записан
|
|
|
|
Джон
просто
Администратор
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."
|
|
|
|
Джон
просто
Администратор
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."
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
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++ »
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
Джон
просто
Администратор
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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #13 : 24-11-2003 12:37 » |
|
Джон, а если ошибка в программе с двойным освобождением?
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Джон
просто
Администратор
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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #15 : 24-11-2003 13:30 » |
|
Двойное освобождение - это неоднократный вызов освобождения блока памяти. Например, если ты поставишь тот же delete для одного и того же указателя в нескольких местах, а сработает не один, а два. Конечно на нулевой указатель выпадет ошибка - о том и горорит народ - если бы был не 0, то могло ошибки не выдать, но чужие данные попортить.
Зачем нужен if(p) delete p ? Например, указатель - часть некой структуры (или класса) и, по условию алгоритма, необязательно должен указывать на выделеный блок. При вызове ф-ии удаления структуры, надо, прежде чем делатть delete, проверить, занималась ли память для этого указателя.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Джон
просто
Администратор
Offline
Пол:
|
|
« Ответ #16 : 24-11-2003 13:50 » |
|
Наверно я неправильно говорю. Вот что я имею ввиду: int *p = NULL; p = new int(3); delete p; p=NULL; где-нить delete p; вместо if(p) delete p; !!!!! Двойное освобождение - это неоднократный вызов освобождения блока памяти. Например, если ты поставишь тот же 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
Молодой специалист
Offline
Пол:
|
|
« Ответ #17 : 24-11-2003 22:42 » |
|
Ну, ребята, вы и туману напустили... кстати, Sashok, проверка типа
if(data != NULL) delete data;
не нужна, ты можешь delete вызывать и с нулевым указателем, даже если один раз delete был вызван, то указатель от этого не обнуляется те он не NULL поэтому при повторном вызове delete произойдёт удаление уже удалённего блока - ERROR. Ты совершенно правильно обосновал, почему она как раз нужна: чтобы не было повторного удаления блока. А в коде, который я написал, я почему-то не включил ( :oops: ) еще одну строчку, хотя в тексте в явном виде упомянул: обнуление пойнтера. На настоящий момент сообщение отредактировано! Насчет смарт-пойнтеров: именно для того, чтобы сразу не морочить человеку голову смарт-пойнтерами я и начал ответ с фразы: при работе с обычным пойнтером, как в С... Если же говорить о смарт-пойнтерах, то прежде надо выяснить, знаком ли человек с перегрузкой операторов. ИМХО.
|
|
|
Записан
|
Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
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++ »
|
Записан
|
|
|
|
Джон
просто
Администратор
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
Молодой специалист
Offline
Пол:
|
|
« Ответ #23 : 25-11-2003 16:31 » |
|
А помоему, Джон прав. Зачем вам проверка указателя? Применим delete без проверки в трех случаях: 1. указатель валидный -> OK 2. указатель = 0 -> OK 3. указатель "убитый", но != 0 -> Error! Если мы используем проверку перед удалением, результаты будут такими же как и без проверки. SAA, Джон, да вы что - в трех соснах заблудились? Как раз вариант 3. и недопустим, это же повторное освобождение памяти! Тот самый Error!. А если при каждом освобождении указатель обнулять, то как раз третьего варианта не будет. Надеюсь, что в полезности обнулять указатель немедленно после освобождения я вас убедил. Теперь о проверке. Да, delete к нулю применять можно. Но есть еще один момент: если программа добралась до кода, где не известно, указатель действительный, или уже освобожденный, она ничего не может с ним делать без проверки, кроме освобождения, да и освобождение допустимо только, если в указателе ноль. С точки зрения вероятности внести ошибку, на мой взгляд, хороший стиль заключается в том, чтобы везде в коде, где не известно истинное состояние указателя проверять его на ноль, а при освобождении - всегда обнулять.
|
|
|
Записан
|
Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #25 : 25-11-2003 22:30 » |
|
Serega - даешь статью по smart-poinetrs!
Суппорт.
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
Джон
просто
Администратор
Offline
Пол:
|
|
« Ответ #26 : 26-11-2003 11:56 » |
|
Sashok, Ну хорошо, сделаем подругому. Объясни в чём разница выполнения этого кода: if(p!=NULL) delete p; p=NULL;
от этого: delete p; p=NULL;
Что будет по-другому? А если при каждом освобождении указатель обнулять, то как раз третьего варианта не будет. Надеюсь, что в полезности обнулять указатель немедленно после освобождения я вас убедил.
Читай, что я в первом топике написал. Правило 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
Помогающий
Offline
|
|
« Ответ #27 : 26-11-2003 12:49 » |
|
"Слушал я вас слушал, долго и внимательно" (С) Кто сказал, что неинициализированный указатель равен 0? В VC не равен, просто по определению. Даже в дебаг версии. А про релиз я даже не говорю.
|
|
|
Записан
|
|
|
|
Джон
просто
Администратор
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."
|
|
|
Джон
просто
Администратор
Offline
Пол:
|
|
« Ответ #29 : 26-11-2003 12:58 » |
|
Кто сказал, что неинициализированный указатель равен 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."
|
|
|
|