Здравствуйте, Critical Error, Вы писали:
I>>Ну, например, перед первым элементом массива может храниться его размер. При попытке при помощи delete[] удалить не массив, а отдельный объект, за размер будет принято кое-что другое...
CE>Еще раз повторяю, что менаджер памяти перед любым куском памяти будь то массив или один элемент хранит размер этого массива или этого элемента. Никаких дополнительных данных нет и не нужны они. Поэтому вызов delete и delete[] для одного объекта абсолютно ничем не отличаются. Я както непонятно выражаюсь?
Понятно. Но не верно. Дополнительные данные нужны.
Да менежер памяти перед любым куском памяти хранит размер этого куска. Но это не "размер массива". И размер массива из размера куска вывести однозначно в общем случае нельзя. Если разделить размер куска на размер элемента массива, то результат получится в общем случае больше, чем размер указанный в 'new[]'. Поэтому, в случае необходимости выозва деструкторов по 'delete[]', в начале блока памяти, выделенном по 'new[]' хранятся два размера: во-первых, хранится размер сырого блока (тот самый размер, о котором ты говоришь), во-вторых, хранится еще и размер массива, указывавшийся в 'new[]' при выделении.
Вызов 'delete' и 'delete[]' для одного объекта будут совпадать только в том случае, если это объект не имеет деструктора (или имеет тривиальный деструктор). А вот если окажется что этот объект имеет нетривиальный деструктор, то вызовы 'delete' и 'delete[]' для него будут отличаться. И отличаться сильно.
Все вышесказанное является деталями "традиционной" реализации (MSVC 6, GCC). В конкретных реализациях все может быть по-другому.
Здравствуйте, CompileError, Вы писали: CE>Короче, окончательно затуманили мой мозг! Спасибо...
Кароче всё просто: если ты создал объект с помощью new, то удалять его надо с помощью delete.
А если создал массив объектов с помощью new[], то удалять его надо с помощью delete[].
Если ты сделаешь не так, никто не гарантирует как и когда упадёт твоя программа.
Что конкретно произойдёт в случае той или другой ошибки, сильно зависит от операционки, компилятора, опций оного, фазы луны и температуры за бортом.
Ну и по общим принципам кодирования/дизайна — смешивть объект и массив объектов плохой, негодный дизайн.
Здравствуйте, LaPerouse, Вы писали:
LP>Если я не ошибаюсь, размер массива и так хранится, при условии, что массив расположен в динамической памяти (т е в случае, если delete вообще применим).
Внутреннее устройство кучи — личное дело конкретной реализации.
Возможны варианты, когда не нужно хранить размер занятого блока рядом с блоком. Например, когда размер блока определяется прямо из адреса (есть пулы блоков разного размера).
К тому же, для менеджера кучи нужно знать именно размер блока, который кратен величине гранулярности. Например, для небольших блоков — 16 байт, а для больших — 16 кбайт.
Количество объектов, помещающихся в блок или реально в нём размещённых — это разные величины
LP>Что касается цикла по объектам, то его можно избежать, если трактовать delete именно как уничтожение массива. Как же тогда уничтожить первый элемент? Просто — явным обращением [index], т е это должна быть забота компилятора.
Да пожалуйста. Всегда выделяй память через new[] и грохай через delete[]. И только там, где тебе заведомо известно, что это один элемент, и ты хочешь сэкономить на спичках — пользуйся new/delete.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, LaPerouse, Вы писали: LP>>Что касается цикла по объектам, то его можно избежать, если трактовать delete именно как уничтожение массива. Как же тогда уничтожить первый элемент? Просто — явным обращением [index], т е это должна быть забота компилятора. К>Да пожалуйста. Всегда выделяй память через new[] и грохай через delete[]. И только там, где тебе заведомо известно, что это один элемент, и ты хочешь сэкономить на спичках — пользуйся new/delete.
Только один момент — при этом нужно распрощаться с удалением потомка через указатель на предка.
Ведь только delete учитывает динамический тип, а delete[] использует статический.
Этот момент как-то обошли в данном обсуждении.
Здравствуйте, Tonal-, Вы писали:
T>Только один момент — при этом нужно распрощаться с удалением потомка через указатель на предка. T>Ведь только delete учитывает динамический тип, а delete[] использует статический. T>Этот момент как-то обошли в данном обсуждении.
Опаньки, и действительно!
А с другой стороны, динамический массив потомков — хоть ты его new[], хоть как угодно создай — будет статически несовместим с предками. Потому что адресная арифметика уплывёт.
Следовательно, нужно или избегать таких ситуаций, или инкапсулировать. Ну а раз инкапсуляция, то можно и placement new/delete задействовать — как это делает тот же vector.
S>typedef
S> int
S> some_type[10];
S>some_type * h= new some_type; /* вроде это преобразуется в: new int[10] */
S>delete h;
S>
И что?
Обманул сам себя — получай UB.
Можно было назвать не some_type а some_array, тогда бы удаление по delete[] выглядело бы естественно.
Или в структурку завернуть:
Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено.
Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло.
Например:
Здравствуйте, Left2, Вы писали:
CE>>А я говорю, что это хорошо? Я объяснил как работает delete[] и только. Выводы делайте сами, вы же программисты. L>Ты предположил как работает delete[]. И посоветовал воспользоваться этим предположением. Я категорически против использования таких советов, о чём и написал. Ну и опять же — по твоему сообщению нельзя понять насколько серьёзно ты это предлагаешь. По нику в форуме никто не может определить уровень твоей квалификации. В итоге запросто человек неопытный может принять этот совет за чистую монету и использовать такое извращение в "боевом" коде.
Ну там же написано, что совет от критической ошибки
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Tonal-, Вы писали:
T>>Только один момент — при этом нужно распрощаться с удалением потомка через указатель на предка. T>>Ведь только delete учитывает динамический тип, а delete[] использует статический. T>>Этот момент как-то обошли в данном обсуждении.
К>Опаньки, и действительно! К>А с другой стороны, динамический массив потомков — хоть ты его new[], хоть как угодно создай — будет статически несовместим с предками. Потому что адресная арифметика уплывёт. К>Следовательно, нужно или избегать таких ситуаций, или инкапсулировать. Ну а раз инкапсуляция, то можно и placement new/delete задействовать — как это делает тот же vector.
Здравствуйте, Tonal-, Вы писали:
S>>А если так? S>>
S>>typedef
S>> int
S>> some_type[10];
S>>some_type * h= new some_type; /* вроде это преобразуется в: new int[10] */
S>>delete h;
S>>
T>И что? T>Обманул сам себя — получай UB. T>Можно было назвать не some_type а some_array, тогда бы удаление по delete[] выглядело бы естественно. T>Или в структурку завернуть: T>
T>Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено. T>Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло. T>Например: T>
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, Tonal-, Вы писали:
S>>>А если так? S>>>
S>>>typedef
S>>> int
S>>> some_type[10];
S>>>some_type * h= new some_type; /* вроде это преобразуется в: new int[10] */
S>>>delete h;
S>>>
T>>И что? T>>Обманул сам себя — получай UB. T>>Можно было назвать не some_type а some_array, тогда бы удаление по delete[] выглядело бы естественно. T>>Или в структурку завернуть: T>>
T>>Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено. T>>Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло. T>>Например: T>>
Здравствуйте, Tonal-, Вы писали:
T>Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено. T>Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло.
в отладчике оверхеад видно. посдедняя цифра в [] не 0.
Здравствуйте, Кодт, Вы писали:
К>Да пожалуйста. Всегда выделяй память через new[] и грохай через delete[]. И только там, где тебе заведомо известно, что это один элемент, и ты хочешь сэкономить на спичках — пользуйся new/delete.
есть еще new A() и new A(орлор,олдол,йцуцй)
так что для автоматического удаления по выходу из контекста (тоесть ретурн далеко, а то и не один) велосипед нужен или 2 отдельных.
Это что за бред такой?! Ты полагаешься на какие-то особенности выделения памяти на каком-то конкретном компиляторе и платформе. Более того, я думаю что это даже на том-же компиляторе не завалится, если чуть чуть поменять настройки или например, тип будет с какой-нибудь виртуальным наследованием или еще какой особенностью. И это не называется "велосипед" — это, скорее можно отнести к разряду опасных багов.
P>А все смарт посему не катят
Смарт или не смарт — это не важно. Если выделял массив — удаляй как массив. Если как один объект — удаляй соответственно. Точка. Третьего не дано. А если в коде не знаешь как был выделен указатель — выбрось такой код на помойку, или перепиши нафиг.
"To protect people you must slay people. To let people live you must let people die. This is the true teaching of the sword."
-Seijuro Hiko, "Rurouni Kensin"
А разве я обещал что-то гарантировать я даже в релизе эту вещь не проверял. И вообще не понитаю зачем в 32 нужна грануляция больше 4. Но здесь по дизайну нужно 2 константных, без оператора= один типа режеренс, для симуляции автоматической (автоматической в семантике С++) переменной, второй для симуляции автоматического массива.
Re[2]: delete и delete[ ]
От:
Аноним
Дата:
08.03.07 14:11
Оценка:
Здравствуйте, Шахтер, Вы писали:
Ш>На самом деле, весьма вероятно, что произойдет разрушения кучи. Не вызов деструкторов по сравнению с этим -- мелкое хулиганство.
Не "мелкое хулиганство", а утечка памяти. При работе в цикле это очень быстро способно вычерпать всю память и поставить машину на колени.
Например, недавно поступила жалоба, что некоторая софтина сжирает гиг памяти. Выяснилось, что причина — утечки памяти. Небольшие, но регулярные.
Re[8]: delete и delete[ ]
От:
Аноним
Дата:
08.03.07 14:21
Оценка:
Здравствуйте, MikelSV, Вы писали:
MSV>Может не совсем правильное, но быстрое решение задачи
Мой дорогой друг, желаю Вам скорейшего попадания в большую команду, где любое скорейшее но не совсем правильное решение будет вылезать на глаза. Тогда оптимизма у Вас поубавится. А сейчас Вы просто живете за счет Вашего последователя, бездумно сваливая на его голову ворох Ваших нерешенных проблем.
И уж он Вас вспомнит не раз и не два, делом и словом. Коротким, но не совсем добрым