tag:blogger.com,1999:blog-10303035.post7150705833201278821..comments2024-02-04T23:20:04.066+03:00Comments on Алёна C++: Зачем нужно выражение delete[]Alenahttp://www.blogger.com/profile/09389124127364799922noreply@blogger.comBlogger52125tag:blogger.com,1999:blog-10303035.post-89851903692489283302011-09-03T23:17:22.807+04:002011-09-03T23:17:22.807+04:00int *p_var = new int;
int *p_array = new int[50];
...int *p_var = new int;<br />int *p_array = new int[50];<br /> <br />delete[] p_array;<br />delete p_var;Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-32823259549151616482011-04-27T22:09:30.785+04:002011-04-27T22:09:30.785+04:00Кстати, delete[] и delete различаются только для т...Кстати, delete[] и delete различаются только для типов, имеющих деструктор. К примеру, для встроеных типов никаких sizeof(size_t) байт перед первым экземпляром в блоке выделяться под хранение кол-во объектов не будет.<br />Это всё только наблюдения, аподиктически ничего не утверждается, к примеру, я чисто с потолка взял sizeof(size_t) как самое очевидное для описание размера в 4 байта на моей виндовой платформе. Мейби, в стандарте где-то и указаны такие детали поведения delete и delete[].Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-50928838599435155662011-04-27T21:59:37.381+04:002011-04-27T21:59:37.381+04:00На самом деле дела обстоят так.
delete и delete[] ...На самом деле дела обстоят так.<br />delete и delete[] - это совсем разные вещи. delete вместе с new - это выделение памяти, грубо говоря - это контролируемый и перегружаемый аналог malloc/free / HeapAlloc/HeapFree и любой другой кучи (просто примеры, конечно).<br />А delete [] делает совсем другое. Он берёт кол-во элементов массива, хранящееся в предыдущих (!) 4 байтах (в общем случае, размер size_t) перед экземпляром первого класса и крутит цикл, в котором вызывает DTOR-ы объектов столько раз, сколько там указано. Ну а new[], собственно, перед вызовом конструкторов кладет туда это кол-во. И размер блока кучи тут совершенно ни при чем. Собственно, всё это можно проверить, скомпилировав такой код:<br /><br />std::string a1;<br />std::string* a2 = &a1;<br />delete [] a2;<br /><br />и посмотрев его в дизасме (std::string тут взят для примера, разглядеть всю эту логику намного проще с минимальной генерацией 'поддерживающего' кода - т.е. с отключенными /defaultlib и т.д.)Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-54402278355955859432011-04-26T23:00:57.282+04:002011-04-26T23:00:57.282+04:00ВНИМАНИЕ!!! delete [] вызывает деструкторы для каж...ВНИМАНИЕ!!! delete [] вызывает деструкторы для каждого элемента массива, а delete вызывает лишь один деструктор, то есть:<br />T[5] a;<br />delete a;<br />Конструктор вызван 5 раз, а деструктор 1. Мне это сказал препод по проге, так что инфа 100%Askar Safinhttps://www.blogger.com/profile/08042115742476167057noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-59728027649388145522011-03-23T19:15:37.957+03:002011-03-23T19:15:37.957+03:00а можно ли всегда и во всем использовать delete []...<i>а можно ли всегда и во всем использовать delete []?</i><br />При использовании <b>delete[]</b> для "всего" возникают 2 неоднозначности:<br />1. <b>delete[]</b> не работает с динамическими типами - всегда только статмические. Т. е. при попытке удалить экземпляр порождённого класса через указатель на базовый, вызовется деструктор базового, т. к. С++ не предоставляет полиморфных массивов.<br />2. Количество разрушаемых элементов нужно как-то узнавать. Но если использовать один и тот же оператор и для единичных объектов, и для массивов, то придётся делать одинаковый механизм для тех и других.<br />Пусть, например, мы решили сохранять количество элементов перед массивом (по отрицательному смещению) - тогда придётся так же поступать и для единичного объекта. Т. е. перед каждым объектом сохранять количество - 1. :)<br />Или другой вариант - можно узнать количество, если поделить нацело размер занимаемого блока на размер элемента. Но что делать если это экземпляр порожденного класса, который занимает совсем другой размер чем базовый?<br /><br />В общем причина непоняток в том, что объект и массив объектов - это таки разные типы, но в языках С/С++ указатель на объект и указатель на массив неявно приводятся, и работая с динамическими массивами, мы вынуждены оперировать указателем на первый элемент.<br />Т. е. компилятор просто не можето отличить идёт ли работа с динамическим массивам или с отдельным элементом. А вынесение этого в рантайм неизбежно приведёт к пенальти по размеру или скорости при работе с динамической памятью...tonalhttps://www.blogger.com/profile/06453567280314506179noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-15404869028982321292011-03-21T21:24:14.274+03:002011-03-21T21:24:14.274+03:00undefind behaviour ждатьundefind behaviour ждатьAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-12780114369357574922011-03-18T01:37:07.856+03:002011-03-18T01:37:07.856+03:00Ну то, что нельзя массив удалять delet'ом, как...Ну то, что нельзя массив удалять delet'ом, как бы выяснили. Возникает другой вопрос: а можно ли всегда и во всем использовать delete []? Т.е. чего ждать если какой нибудь<br /><br />int *p=new int(5);<br />//удалить так<br />delete [] p; //?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-72642056393976929402010-05-21T07:51:28.515+04:002010-05-21T07:51:28.515+04:00Наконец, вы меня успокоили, что можно писать delet...<i>Наконец, вы меня успокоили, что можно писать delete везде без сомнительных скобок</i><br />Нужно не "успокаиваться интернетом" а разбираться с непонятными вопросами.<br />Тогда вместо глупости типа <i>"<b>delete</b> везде без сомнительных скобок"</i> просто будешь правильно расставлять скобки. :)tonalhttps://www.blogger.com/profile/06453567280314506179noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-6828223069096714182010-05-20T18:51:58.384+04:002010-05-20T18:51:58.384+04:00Я не конкретно про вас Алена. Я про Интернет. Он м...Я не конкретно про вас Алена. Я про Интернет. Он меня успокоил, в т.ч. и этот блог.Alexhttps://www.blogger.com/profile/01210744251902416901noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-65935710768780933912010-05-20T18:50:03.376+04:002010-05-20T18:50:03.376+04:00Alex:
Наконец, вы меня успокоили, что можно писат...<b>Alex:</b><br /><br /><i>Наконец, вы меня успокоили, что можно писать delete везде без сомнительных скобок</i><br /><br />Нет, такого я не писала. delete[] нужно использовать при работе с массивами.Alenahttps://www.blogger.com/profile/09389124127364799922noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-20602209886421299932010-05-20T18:42:56.313+04:002010-05-20T18:42:56.313+04:00Наконец, вы меня успокоили, что можно писать delet...Наконец, вы меня успокоили, что можно писать delete везде без сомнительных скобок. Почитал в Интернете, что по этому поводу пишут. Как я выяснил вся разница в (возможно) производительности. Также есть такие несущественные детали как вызов конструкторов для отдельных объектов и (НЕПОНЯТНО!!!) кому нужная перегрузка операторов new/new[] и delete/delete[].<br /><br />Я предпочитаю никогда не писать код типа new Object [100]; Я всегда использую массивы указателей m = new *Object[100]. И потом for (...) m[i] = new Object; Указатели не имеют деструкторов, а удалять объекты гораздо понятнее через for (...) delete m[i]; delete m; где Object *m[100]; например.<br /><br />delete[] очень сложно всегда помнить. Что касается векторов, то у меня в проектах они реализованы в наших библиотеках, а не в std, т.к. на 20 ОС, которые нужно поддерживать явно нельзя рассчитывать на отсутствие багов в той или иной библиотеке std.Alexhttps://www.blogger.com/profile/01210744251902416901noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-52277803202954358012009-12-07T12:52:16.393+03:002009-12-07T12:52:16.393+03:00Для блока памяти известен его размер.
При удалении...Для блока памяти известен его размер.<br />При удалении массива компилятор знает тип его элемента.<br />Поэтому количество элементов он очень просто вычислит.<br />Стало быть, delete[n] - излишен.<br /><br />А вот различить на что указывает указатель - на массив или на один элемент компилятор не может - синтаксически ситуации не различимы.<br />Поэтому без деления на delete и delete[] не получается.tonalhttps://www.blogger.com/profile/06453567280314506179noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-4998898923350397072009-12-07T10:56:35.794+03:002009-12-07T10:56:35.794+03:00По-моему в одной из публикаций Страуструпа, было н...По-моему в одной из публикаций Страуструпа, было написано, что оператор освобождения памяти для массивов должен был выглядеть так:<br /><br />delete[n] ptr; // ptr указывает на массив из n элементов<br /><br />В этом случае компилятору не нужно было сохранять информацию о кол-ве элементов. А уже потом его решили сократить до:<br /><br />delete[] prt;Unknownhttps://www.blogger.com/profile/14329729770496878553noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-74921783873001783612009-03-01T23:04:00.000+03:002009-03-01T23:04:00.000+03:002Анонимный:Т.е. создал что-то c [] незабудь, это ч...<B>2Анонимный:</B><BR/><BR/><I>Т.е. создал что-то c [] незабудь, <BR/>это что-то [] освободить. </I><BR/><BR/>Люди будут забывать. Можно этому удивляться, можно над этим потешаться, но если у нас есть что-то с пометкой "не забыть", то это - потенциальный источник неприятностей. Причем наступать на эти грабли будут и новички, и опытные программисты. И выясняться это будет в самый неподходящий момент.Alenahttps://www.blogger.com/profile/09389124127364799922noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-43758568743919061112009-02-26T10:51:00.000+03:002009-02-26T10:51:00.000+03:00Случайно наткнулся на эту ветку. И очень удивился,...Случайно наткнулся на эту ветку. И очень удивился, что delete [] мешает кому-то жить. Скажу так, что во-первых delete [] - вносит ясность в код, что удаляем именно массив, а не что-то еще. Т.е. создал что-то c [] незабудь, это что-то [] освободить. Когда код будет читать кто-то еще запись без скобок логически может быть неясна!. Второе, вообще не понял зачем городить какие-то границы массива. Не забываем, что массив это указатель на область памяти и всё... Для всяческих приятных извратов есть vector, list и т.д. Т.е. я хочу сказать, что реализация массива в С++ это самый низкий уровень, и программисту предоставляется ВЫБОР: или оптимизация и колбасня с указателями или простота вектора, списка и т.п.<BR/><BR/>Ух, <BR/>Я за простой и понятный код!<BR/><BR/><BR/>P.S. <BR/>А есть еще тип char* ... который окaнчивается /0 - и чтобы выбрать элементы нам достаточно знать только это, а не количество символов.... (это к слову о границах массива)<BR/><BR/><BR/>А также можно написать:<BR/><BR/>char *a=new char [20];<BR/>strcpy (a,"Hello World");<BR/>a[5]='_'; <BR/><BR/><BR/>//Цена разницы синтаксиса<BR/>delete a; //Освободили только первый элемент -- утечка памяти<BR/>delete [] a; //Освободили все<BR/><BR/>//Отношение к памяти должно быть бережное несмотря на ее количество.<BR/><BR/>//Тот кто считает, что освобождать память не нужно - не должен писать программы на С и С++. Для этого есть Basic, Java, и .т.п.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-47733589576845781332008-12-08T03:17:00.000+03:002008-12-08T03:17:00.000+03:00Программист я не достаточно опытный, конечно... Но...Программист я не достаточно опытный, конечно... Но всё же работая уже над своим вторым движком и менеджером памяти к нему, до сих пор ловлю себя на мысли с таким "дурацким" вопросом.<BR/><BR/>2Алёна: Спасибо за ведение такого замечательного блога - не первый раз обнаруживаю обсуждение интересных тем.=)Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-9381585892474508882008-09-30T16:57:00.000+04:002008-09-30T16:57:00.000+04:00Хм.. мне тоже странно. Почему бы компилятору не пр...Хм.. мне тоже странно. Почему бы компилятору не привести delete к delete[]? Ведь по сути там только надо добавить количество элементов в структуру, создаваемую new. А если это нельзя, то почему бы не выдавать предупреждение если используется delete вместо delete[]?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-45343077796803499872008-07-16T11:42:00.000+04:002008-07-16T11:42:00.000+04:00А так программисту приходится всегда помнить, что ...<I>А так программисту приходится всегда помнить, что именно вызывать для освобождения памяти: delete или delete[]. Зачем - не очень понятно. Информация о том, сколько именно элементов в массиве все равно где-то да хранится. Почему бы компилятору вообще не освободить программиста от каких-либо запоминаний?</I><BR/><BR/>Очень странный вопрос для опытного программиста на С++ :) Его задают на собеседовании, что бы отсеять новичков.<BR/><BR/>Что бы понять разницу предлагаю прогнать пару раз такую программу:<BR/><BR/><B><BR/>#include <stdio.h><BR/><BR/>class Test<BR/>{<BR/>public:<BR/><BR/> ~Test()<BR/> {<BR/> puts("~");<BR/> }<BR/>};<BR/><BR/>int main(int, char**)<BR/>{<BR/> Test *a = new Test[2];<BR/><BR/>// пробуем два варианта<BR/>// delete a;<BR/> delete[] a;<BR/><BR/> return(0);<BR/>}<BR/></B>Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-24459073540498973992008-06-03T18:21:00.000+04:002008-06-03T18:21:00.000+04:002Анонимный:Хм... ведь известен размер выделенной о...<B>2Анонимный:</B><BR/><I>Хм... ведь известен размер выделенной области памяти и размер удаляемого типа данных, соответсвенно можно определить кол-во элементов в массиве. Получается, что в delete[] нет необходимости. Или я не прав?</I><BR/><BR/>Дык эта, о том и пост. :-)Alenahttps://www.blogger.com/profile/09389124127364799922noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-78304642608202339172008-06-03T13:55:00.000+04:002008-06-03T13:55:00.000+04:00Хм... ведь известен размер выделенной области памя...Хм... ведь известен размер выделенной области памяти и размер удаляемого типа данных, соответсвенно можно определить кол-во элементов в массиве. Получается, что в delete[] нет необходимости. Или я не прав?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-10303035.post-1021515792265747432008-03-23T14:27:00.000+03:002008-03-23T14:27:00.000+03:00Мне кажется, все эти непонятки с указателями проис...Мне кажется, все эти непонятки с указателями происходят от того, что плюсы, вслед за С смешивают 2 понятия : указатель на структурированную область памяти, которая может быть размешена в куче, и итератор по массиву.<BR/>Соответственно, если эти понятия разнести - сделать для них разные типы, то проблемы сразу кончатся. :-)<BR/>Компилятор будет знать, что удалять по итераторам нельзя - и не даст.<BR/>Ну а при удалении по указателю, тип его будет статически известен, и компилятор сможет сгенерить нужный код без каких-нибудь затрат во время выполнения.<BR/><BR/>Останутся проблемы несовместимости с С, где понятия смешаны.<BR/>С другой стороны, можно ввести новую типизацию параллельно старой - как сделано с приведениями, например.<BR/><BR/>P.S. Я на вскидку не смог придумать алгоритм, где бы эти типы нельзя бы было тривиально разделить. :-)tonalhttps://www.blogger.com/profile/06453567280314506179noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-56943550523350707962008-03-21T22:39:00.000+03:002008-03-21T22:39:00.000+03:00Есть стандарт там всё сказано....char *a = new cha...Есть стандарт там всё сказано....<BR/><BR/>char *a = new char;<BR/>char *b = new [10];<BR/><BR/>delete[] a; поведение не определено<BR/>delete b; поведение не определено<BR/><BR/>соотвественно как сказано выше если реализовать не так как в стандарте то будет не соответствие стандарту :) кстати это же не один неопределенный случай.... а про внутренности тут уже всё от автора компилятора зависит.... так же как в стандарте не описана реализация внутренностей класса так и компиляторы делают её по своему например g++ и msvc++ ^)Fallouthttps://www.blogger.com/profile/12723306287383678908noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-64030246598938083322008-03-08T03:33:00.000+03:002008-03-08T03:33:00.000+03:00Алёна, я не вдовался в подробности, но скорее всег...Алёна, я не вдовался в подробности, но скорее всего причина использования delete[], в том что некоторые реализаций непонимают разницы между указателем на переменную и именем массива.Rinat Galiulinhttps://www.blogger.com/profile/15934508188322401837noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-9733497255014734122008-01-29T00:35:00.000+03:002008-01-29T00:35:00.000+03:002pesec:Не убедительно, Алёна. Вам уже рассказали, ...<B>2pesec:</B><BR/><I>Не убедительно, Алёна. Вам уже рассказали, что информацию, массив ли это или один объект, нужно где-то хранить. </I><BR/><BR/>Так она уже есть.<BR/><BR/><I>И платить за это! А Строустрап говорил: если не используете -- не плАтите.</I><BR/><BR/>Если нужна какая-нибудь информация, кроме той, которая есть - можно сделать какой-нибудь волшебный ключик. Как с RTTI.Alenahttps://www.blogger.com/profile/09389124127364799922noreply@blogger.comtag:blogger.com,1999:blog-10303035.post-44674462095884488812008-01-28T18:33:00.000+03:002008-01-28T18:33:00.000+03:00Не убедительно, Алёна. Вам уже рассказали, что инф...Не убедительно, Алёна. Вам уже рассказали, что информацию, массив ли это или один объект, нужно где-то хранить. И платить за это! А Строустрап говорил: если не используете -- не плАтите.Anonymousnoreply@blogger.com