NULL? Кто он и с чем его едят...
(заккомментированная строчка при включении не дает никакого эффектА)
#include <stdlib.h>
//#define NULL ((void*)0)
int main(void){
long *a=new long(3);
delete a;
if (a!=NULL)
delete a;
return 1;
}
Стандарт C++ описывает макрос NULL, он определяется в стандартных заголовочных файлах.
Приведенный пример работает так как должен работать и проблема здесь не в NULL, а в операторе delete, который вовсе не обязан обнулять указатель на освобождаемую память.
molnij
Стандарт C++ описывает макрос NULL, он определяется в стандартных заголовочных файлах.
Ну это же тупо! почему для работы с каким-нибудь int'ом ничего не нужно подключать, а для NULL'а нужно!!!
Мнээээ, тогда глупый вопрос, а как я должен узнать освобождена память или нет????? Ведь при втором вызове delete'а выдается ошибка!
Тупо или нет - это вопрос к разработчикам языка, но в любой программе более 3 строчек тебе все ревно придется подключать какие-нибудь заголовки.
как я должен узнать освобождена память или нет??
delete всегда освобождает память, если ей дают правильный указатель.
Ну это же тупо! почему для работы с каким-нибудь int'ом ничего не нужно подключать, а для NULL'а нужно!!!
NULL не тип... а значение :) для MAX_INT тоже надо "ашник" подключать
Мнээээ, тогда глупый вопрос, а как я должен узнать освобождена память или нет????? Ведь при втором вызове delete'а выдается ошибка!
обычно делают так:
...
delete a;
a = NULL;
...
иногда для удобства делают макросы
из примеров DX:
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
long *a=new long(3);
delete a;
if (a!=NULL)
delete a;
return 1;
} [/QUOTE]
Еще одно правило - на один new должен припадать один delete! Аналогично malloc-free.
Ну насчет трех строчек я бы еще поспорил... ну да ладно...
Тогда еще один вопрос. Чем принципиально отличаются delete a и delete[]a? Только не надо объяснять что второй удаляет всю память а первый нет... Вопрос не в этом, можно ли для int *a=new int; юзать delete []a ???
Ну насчет трех строчек я бы еще поспорил... ну да ладно...
Тогда еще один вопрос. Чем принципиально отличаются delete a и delete[]a? Только не надо объяснять что второй удаляет всю память а первый нет... Вопрос не в этом, можно ли для int *a=new int; юзать delete []a ???
Нельзя
(кстати оба оператора удаляют всю выделенную память)
delete[] a используется для удаления массивов т.е. если проще то в тех случаях когда использовалось:
int *a = new int[10]; // выделяем массив из 10 int
Ну насчет трех строчек я бы еще поспорил... ну да ладно...
Тогда еще один вопрос. Чем принципиально отличаются delete a и delete[]a? Только не надо объяснять что второй удаляет всю память а первый нет... Вопрос не в этом, можно ли для int *a=new int; юзать delete []a ???
По стандарту языка для new[] соответствует delete[], а для new - delete.
Но современные компиляторы ошибки такого соответствия обходят без постороней помощи.
int *a = new int[10]; // выделяем массив из 10 int
Не совсем так.
new int[10]; // Создает экземпляр(объект) типа int[10]
Но это уже другая история... :о)
Не совсем так.
new int[10]; // Создает экземпляр(объект) типа int[10]
Но это уже другая история... :о)
Даже не знаю стоит ли углубляться в филососфские различия массива из 10 элементов int и экземпляра объекта типа int[10].....
по моему массив все-таки проще для понимания.. а экземпляры пусть у классов будут...
Тогда еще один вопрос. Чем принципиально отличаются delete a и delete[]a? Только не надо объяснять что второй удаляет всю память а первый нет... Вопрос не в этом, можно ли для int *a=new int; юзать delete []a ???
Ответ зависит от, того какой компилятор ты используешь.
Не поленился, проверил компиляторы от MS и Borland на примере с int'ми. Получились следующие результаты:
В MS VC 6 операторы delete и delete[] транслируются в вызов одной и той же внутренней функции т.е. с позиции пользователя они совершенно одинаковы.
В Borland C++ 5.5 оператор delete реализуется через delete[], здесь тоже получается никакой разницы, можно даже попробовать "оптимизировать" программу: вместо delete[] писать delete, получиться на пару машинных команд меньше :).
Если же ты хочешь присать переносимые программы - придерживайся стандарта. Насколько я понимаю, введением двух операторов delete разработчики стандарта хотели облегчить жизнь создателям компиляторов, но те сказали, что сами с усами,
и обошлись по сути дела одним.
Про 3 строчки, вообще-то я образно выразился: глупо писать программу без заголовков.
Green
new int[10]; // Создает экземпляр(объект) типа int[10]
Оригинально. Это что-то из разряда Think different ?
molnij
В MS VC 6 операторы delete и delete[] транслируются в вызов одной и той же внутренней функции т.е. с позиции пользователя они совершенно одинаковы.
В Borland C++ 5.5 оператор delete реализуется через delete[], здесь тоже получается никакой разницы, можно даже попробовать "оптимизировать" программу: вместо delete[] писать delete, получиться на пару машинных команд меньше :).
не советовал бы таким образом оптимизировать...
Все это хорошо только для простых типов и классов у которых нет деструктора (деструктор по умолчанию)...
попробуйте выполнить код:
{
public:
~CTest() {}
};
int main(int argc, char* argv[])
{
CTest *array = new CTest[10];
delete array;
return 0;
}
при освобождении памяты выделеной new[] необходимо вызывать деструктор для всех элементов... delete пытается вызвать только для одного... да и то скорее всего запутывается с адресами и программа падает.
Так что рекомендую во всех случаях следовать соответсвию new - delete, new[] - delete[] :)
P.S. кстати если в примере закоментировать деструктор то программа перестает падать :)
P.P.S. проверял на VC6.0 и eVC3.0
А зачем вобще нужен этот NULL? Поему просто 0 понятней и красивей. Да и Страуструп рекомендует 0 использовать.
хм..... традиция-с....
в принципе одно и тоже хотя на некоторых платформах NULL наверно и не 0 может быть...
По сложным типам данных согласен 100%, тут все намного сложней.
Я писал только про int.
Winnie
По сложным типам данных согласен 100%, тут все намного сложней.
Я писал только про int.
ну да... вобщем такая оптимизация и разряда "dirty trick" т.е. если сильно надо и сильно уверен то можно... но сильно не рекомендуется.. особенно начинающим
А зачем вобще нужен этот NULL? Поему просто 0 понятней и красивей. Да и Страуструп рекомендует 0 использовать.
NULL нужен для того, чтобы не писать (void *)(0)...А просто ноль вообще-то юзать вроде бы нельзя...
А *a=new int; и a=new int[1] как нибудь различаются??
NULL нужен для того, чтобы не писать (void *)(0)...А просто ноль вообще-то юзать вроде бы нельзя...
Можно. Он автоматически преобразуется в void*. И вобще что такое 0? Какого он типа? int, char, void*? 0 разные бывают :) У каждого типа свой :)
А зачем вобще нужен этот NULL? Поему просто 0 понятней и красивей. Да и Страуструп рекомендует 0 использовать.
0 может быть и красивее, но не понятней. Особенно когда разбираешься в чужой программе: если видишь
if (somevar == NULL) {...}
сразу ясно, somevar - это указатель, а не int и не char, как можно подумать глядя на
if (somevar == 0) {...}
Да и существование архитектур, где NULL вовсе не ноль тоже не исключено (хотя я таких не знаю).
И еще, подскажи, где Страуструп рекомендует использовать 0. В 3-ем издании Языка C++ что-то я такого не припомню (возможно ошибаюсь).
Winnie
вобщем такая оптимизация и разряда "dirty trick"
Поставив ковычки и смайлик в исходном посте, я думал народ поймет, что выполнять такую "оптимизацию" не стоит. Извиняюсь, наверное надо было написать подробнее. А вообще ты безусловно прав - выполнять оптимизацию за счет особенностей конкретного компилятора - самое последнее дело. В подавляющем большинстве случаев можно найти способ сделать стандартно и более эффективно.:)
0 может быть и красивее, но не понятней. Особенно когда разбираешься в чужой программе: если видишь
if (somevar == NULL) {...}
сразу ясно, somevar - это указатель, а не int и не char, как можно подумать глядя на
if (somevar == 0) {...}
Да и существование архитектур, где NULL вовсе не ноль тоже не исключено (хотя я таких не знаю).
И еще, подскажи, где Страуструп рекомендует использовать 0. В 3-ем издании Языка C++ что-то я такого не припомню (возможно ошибаюсь).
Иммено в этой книге. К сожалению сейчас ее под рукой нет, страницы не назову. Но где-то в начале, где он объяняет почему в 90% случаев не надо использовать препроцессор :) А про somevar лучше вобще if(!somevar) {...}
Иммено в этой книге. К сожалению сейчас ее под рукой нет, страницы не назову. Но где-то в начале, где он объяняет почему в 90% случаев не надо использовать препроцессор :) А про somevar лучше вобще if(!somevar) {...}
Страуструп. Издание 3-е.
5.1.1. Ноль (стр 128)
Ноль (0) имеет тип int. Благодаря стандартным преобразованиям, 0 можно испоьзовать в качестве констаныт любого интегрального типа, типа с плавающей точкой, указателя или указателя на член класса. ип нуля определяется по контексту. Ноль как правило (но не всегда), будет физически представлен в виде последовательности нулевых битов соответсвующей длины.
Гарантируется, что нет объектов с нулевым адресом. Следовательно, указатель, равный нулю, можно интерпретировать как указатель, который не на что не ссылается.
В языке C очень популярно определять макрос NULL для представления такого нулевого указателя. Так как в C++ типы проверяются более жестко, использование банального нуля вместо NULL приведет к меньшим проблемам. Если вы чуствуете, что просто обязаны определить NULL, воспользуйтесь
const int NULL = 0;
От себя: я предпочитаю все-таки использовать NULL (во-первых традиция-с... во-вторых еще много приходится писать на C а не на C++)
kswapd
Спасибо за подсказку.
P.S. Я тоже за NULL, хотя практически все делаю на C++. Попривычнее как-то.