delete и delete[ ]
От: CompileError  
Дата: 26.01.07 21:38
Оценка:
Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?
Re: delete и delete[ ]
От: Аноним  
Дата: 26.01.07 21:45
Оценка:
да
Re: delete и delete[ ]
От: nrwl  
Дата: 26.01.07 21:55
Оценка:
Здравствуйте, CompileError, Вы писали:

CE>Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?


При условии, что массив объектов создавался с помощью new[] — да.
delete и delete[ ]
От: Андрей Тарасевич Беларусь  
Дата: 26.01.07 22:12
Оценка: +4
#Имя: FAQ.cpp.deletearr
Здравствуйте, CompileError, Вы писали:

CE>Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?


Есль речь идет о массиве в динамической памяти, то удалять его нужно при помощи 'delete[]'. Попытка же удаления через 'delete' ведет к неопределеннному поведению. Именно к неопределеннному поведению. Все.

А всякое "не будут вызваны деструкторы" — это уже гадание на кофейной гуще, к делу никак не относящееся.
Best regards,
Андрей Тарасевич
Re[2]: delete и delete[ ]
От: LaPerouse  
Дата: 26.01.07 23:23
Оценка: -1 :))) :)
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, CompileError, Вы писали:


CE>>Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?


АТ>Есль речь идет о массиве в динамической памяти, то удалять его нужно при помощи 'delete[]'. Попытка же удаления через 'delete' ведет к неопределеннному поведению. Именно к неопределеннному поведению. Все.


АТ>А всякое "не будут вызваны деструкторы" — это уже гадание на кофейной гуще, к делу никак не относящееся.



Вот это-то меня и напрягает в С++. В данном случае логичнее было бы иметь один вид уничтожения объекта (delete), чтобы тем самым уничтожить весь массив, ну, или на худой конец, его первый элемент. Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[3]: delete и delete[ ]
От: Daevaorn Россия  
Дата: 27.01.07 08:40
Оценка: +1
Здравствуйте, LaPerouse, Вы писали:

LP>Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.

А не лучше просто писать правильный код и не сетовать на разработчиков компилятора?
Re[2]: delete и delete[ ]
От: CompileError  
Дата: 27.01.07 09:17
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, CompileError, Вы писали:


CE>>Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?


АТ>Есль речь идет о массиве в динамической памяти, то удалять его нужно при помощи 'delete[]'. Попытка же удаления через 'delete' ведет к неопределеннному поведению. Именно к неопределеннному поведению. Все.


АТ>А всякое "не будут вызваны деструкторы" — это уже гадание на кофейной гуще, к делу никак не относящееся.


Все понятно, спасибо.
Re: delete и delete[ ]
От: Шахтер Интернет  
Дата: 27.01.07 10:12
Оценка:
Здравствуйте, CompileError, Вы писали:

CE>Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?


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

При конструировании массива объектов с нетривиальным деструктором оператором new[] к массиву объектов будет добавлен небольшой префикс, содержащий в частности число элементов массива.
Вернет же оператор указатель на первый элемент массива. Т.е. этот указатель не указывает на первый байт выделенного блока памяти. Поэтому при вызове простого delete ему будет передан неверный указатель на блок памяти, что приведет к разрушению кучи (или к abort у, если куча с защитой).
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: delete и delete[ ]
От: LaPerouse  
Дата: 27.01.07 10:23
Оценка: +1
Здравствуйте, Daevaorn, Вы писали:

D>Здравствуйте, LaPerouse, Вы писали:


LP>>Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.

D>А не лучше просто писать правильный код и не сетовать на разработчиков компилятора?

Не на разработчика компилятора, а на разработчиков стандарта
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[3]: delete и delete[ ]
От: Erop Россия  
Дата: 27.01.07 11:10
Оценка: +1
Здравствуйте, LaPerouse, Вы писали:

LP>Вот это-то меня и напрягает в С++. В данном случае логичнее было бы иметь один вид уничтожения объекта (delete), чтобы тем самым уничтожить весь массив, ну, или на худой конец, его первый элемент. Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.


Да какая проблема?
Пользуйся std::vector, вместо new [] да и всё
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: delete и delete[ ]
От: vasmann  
Дата: 28.01.07 11:42
Оценка:
Здравствуйте, LaPerouse, Вы писали:

LP>Здравствуйте, Daevaorn, Вы писали:


D>>Здравствуйте, LaPerouse, Вы писали:


LP>>>Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.

D>>А не лучше просто писать правильный код и не сетовать на разработчиков компилятора?

LP>Не на разработчика компилятора, а на разработчиков стандарта


А как Вы себе представляете унифицированный опереатор new и delete?
Ведь если вы просто выделяете память то Вам надо просто вернуть указатель, а если блок памяти (читай динамический массив) то помимо указателя нужно выделить еще как минимум 4 байта для храниения кол-ва обьектов. А отсюда вытекает что если вы хотите унифицироавнные опереаторы — то получите всегда дополнительные 4 байта плюс не нужные оператор цикла (даже для одного элемента) — а это НИКОМУ не нада. И действительно что мешает писать правильно? И еще: лучше использовать std::vector — все вопрсы решены. Ну или либу boost (www.boost.org).
Re[6]: delete и delete[ ]
От: Erop Россия  
Дата: 28.01.07 14:56
Оценка: +1
Здравствуйте, vasmann, Вы писали:

V>А как Вы себе представляете унифицированный опереатор new и delete?

V>Ведь если вы просто выделяете память то Вам надо просто вернуть указатель, а если блок памяти (читай динамический массив) то помимо указателя нужно выделить еще как минимум 4 байта для храниения кол-ва обьектов. А отсюда вытекает что если вы хотите унифицироавнные опереаторы — то получите всегда дополнительные 4 байта плюс не нужные оператор цикла (даже для одного элемента) — а это НИКОМУ не нада. И действительно что мешает писать правильно? И еще: лучше использовать std::vector — все вопрсы решены. Ну или либу boost (www.boost.org).


Ну, вообще говоря, проблема в том, что new[] возвращает указатель на первый элемент массива, а не на "массив элементов созданный динамически".

Вообще говоря никто не мешал сделать всё безопасно, но увы, "не в этой очередно йальфа-версии языка С++"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: delete и delete[ ]
От: LaPerouse  
Дата: 28.01.07 19:02
Оценка:
Здравствуйте, vasmann, Вы писали:

V>Здравствуйте, LaPerouse, Вы писали:


LP>>Здравствуйте, Daevaorn, Вы писали:


D>>>Здравствуйте, LaPerouse, Вы писали:


LP>>>>Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.

D>>>А не лучше просто писать правильный код и не сетовать на разработчиков компилятора?

LP>>Не на разработчика компилятора, а на разработчиков стандарта


V>А как Вы себе представляете унифицированный опереатор new и delete?

V>Ведь если вы просто выделяете память то Вам надо просто вернуть указатель, а если блок памяти (читай динамический массив) то помимо указателя нужно выделить еще как минимум 4 байта для храниения кол-ва обьектов. А отсюда вытекает что если вы хотите унифицироавнные опереаторы — то получите всегда дополнительные 4 байта плюс не нужные оператор цикла (даже для одного элемента) — а это НИКОМУ не нада. И действительно что мешает писать правильно? И еще: лучше использовать std::vector — все вопрсы решены. Ну или либу boost (www.boost.org).

Если я не ошибаюсь, размер массива и так хранится, при условии, что массив расположен в динамической памяти (т е в случае, если delete вообще применим).

Что касается цикла по объектам, то его можно избежать, если трактовать delete именно как уничтожение массива. Как же тогда уничтожить первый элемент? Просто — явным обращением [index], т е это должна быть забота компилятора.

Поправьте. пожалуйста, если ошибаюсь. Мне на самом деле до этого дела нет, т к только std::vector и использую.
Социализм — это власть трудящихся и централизованная плановая экономика.
Re: delete и delete[ ]
От: Vlad_SP  
Дата: 29.01.07 08:57
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Попытка же удаления через 'delete' ведет к неопределеннному поведению. Именно к неопределеннному поведению. Все.


Не приведешь ли ссылку на пункт Стандарта, это оговаривающий? Как я ни курил Стандарт, на меня не снизошло просветление... Плохо искал, согласен. Так где же оно?
Re[3]: delete и delete[ ]
От: Left2 Украина  
Дата: 29.01.07 11:18
Оценка: +1
LP>Вот это-то меня и напрягает в С++. В данном случае логичнее было бы иметь один вид уничтожения объекта (delete), чтобы тем самым уничтожить весь массив, ну, или на худой конец, его первый элемент. Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.

Предлагаю как кардинальную меру не юзать ни delete[] ни delete вообще — и никогда не возникнет таких проблем
Если нужен динамический массив — юзайте std::vector (в крайнем случае — его самописный аналог).
Если нужен одиночный обьект, создаваемый динамически — то std::auto_ptr, boost::shared_ptr, ATL::CComPtr — ну или самописный аналог на крайняк. Оверхед нулевой или минимальный, а преимущества очевидны.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: delete и delete[ ]
От: Vlad_SP  
Дата: 29.01.07 11:24
Оценка:
Сорри, разобрался. 5.3.5 cl. 2.
Re[4]: delete и delete[ ]
От: Zigmar Израиль  
Дата: 29.01.07 13:19
Оценка: :)
Здравствуйте, Left2, Вы писали:
L>Предлагаю как кардинальную меру не юзать ни delete[] ни delete вообще — и никогда не возникнет таких проблем
L>Если нужен динамический массив — юзайте std::vector (в крайнем случае — его самописный аналог).
L>Если нужен одиночный обьект, создаваемый динамически — то std::auto_ptr, boost::shared_ptr, ATL::CComPtr — ну или самописный аналог на крайняк. Оверхед нулевой или минимальный, а преимущества очевидны.
Вот чего я-бы категорически не советовал делать, так это хранить указатель на динамический массив в std::auto_ptr или boost::shared_ptr. Это как раз таже-самая проблема, с которой началась тема. auto_ptr всегда удаляет объекты через delete (не delete[]!) а shared_ptr — по умолчанию. Так что std::auto_ptr(new int[100]) это самый что не наесть UB. Если нужен автоматический контейнер для дин. массива, курите boost::scoped_array и boost::shared_array.
"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"
Re[5]: delete и delete[ ]
От: Left2 Украина  
Дата: 29.01.07 13:25
Оценка:
Z>Вот чего я-бы категорически не советовал делать, так это хранить указатель на динамический массив в std::auto_ptr или boost::shared_ptr. Это как раз таже-самая проблема, с которой началась тема. auto_ptr всегда удаляет объекты через delete (не delete[]!) а shared_ptr — по умолчанию. Так что std::auto_ptr(new int[100]) это самый что не наесть UB. Если нужен автоматический контейнер для дин. массива, курите boost::scoped_array и boost::shared_array.
а где в моём сообщении призыв хранить массивы в auto_ptr/shared_ptr ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: delete и delete[ ]
От: LaPerouse  
Дата: 29.01.07 20:23
Оценка:
Здравствуйте, Left2, Вы писали:

LP>>Вот это-то меня и напрягает в С++. В данном случае логичнее было бы иметь один вид уничтожения объекта (delete), чтобы тем самым уничтожить весь массив, ну, или на худой конец, его первый элемент. Вместо — этого — неопределенность, которую каждый разработчик компиляторов трактует по своему. GCC, например, грохает первый элемент. Меня, например, это начинает доставать.


L>Предлагаю как кардинальную меру не юзать ни delete[] ни delete вообще — и никогда не возникнет таких проблем

L>Если нужен динамический массив — юзайте std::vector (в крайнем случае — его самописный аналог).
L>Если нужен одиночный обьект, создаваемый динамически — то std::auto_ptr, boost::shared_ptr, ATL::CComPtr — ну или самописный аналог на крайняк. Оверхед нулевой или минимальный, а преимущества очевидны.


Кажется, тут мои слова восприняли буквально. "Это" — означает, само собой, не конкретно вот это, а такой вот подход — когда что-то неопределено, а разработчики компиляторов реализуют каждый так, как понимает.
Социализм — это власть трудящихся и централизованная плановая экономика.
Re: delete и delete[ ]
От: Critical Error ICQ: 123736611
Дата: 30.01.07 09:28
Оценка: -3 :)
Здравствуйте, CompileError, Вы писали:

CE>Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?


При удалении массива объектов с помощью delete[] сначала запускается цикл, который тупо берет адрес массива, затем вызывает деструктор, прибавляет к адресу размер элемента и гоняет цикл пока не выйдет за границу массива.

Так что создан массив с помощью new[] или просто malloc()-ом не важно. Поведение delete и delete[] довольно предсказуемо. Поэтому когда не уверен будет ли в точке удаления один объект или массив объектов, лучше применять delete[]. Если там один элемент — ничего страшного, вызовется деструктор один раз, потеряешь только пару машинных тактов на обработку цикла. Зато никакой неопределенности не будет. Тем более, кто компилятор сам иногда оптимизирует код, превращая delete[] в delete когда надо.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: delete и delete[ ]
От: Zigmar Израиль  
Дата: 30.01.07 09:43
Оценка: +1
Здравствуйте, Critical Error, Вы писали:
CE>При удалении массива объектов с помощью delete[] сначала запускается цикл, который тупо берет адрес массива, затем вызывает деструктор, прибавляет к адресу размер элемента и гоняет цикл пока не выйдет за границу массива.
Ты забыл добавить "В компиляторе A, версии B, с опциями C, на платформе D". Тогда только можно было бы говорить о верности такого предположения.

CE>Поэтому когда не уверен будет ли в точке удаления один объект или массив объектов, лучше применять delete[].

Т.е. ты предлагаешь вместо того, чтоб писать корректный код, полагаться на имлементацию UB в конкретном компиляторе. Отличное, решение, да.
Кстати, ситуации, когда "не уверен как выделялся объект" — не должно быть в принципе.


CE>Если там один элемент — ничего страшного, вызовется деструктор один раз, потеряешь только пару машинных тактов на обработку цикла.

Ничего страшно, ну разве что упадёт разок другой или диск отформатирует... UB и в Африке UB.

CE>Зато никакой неопределенности не будет.

См выше.

CE>Тем более, кто компилятор сам иногда оптимизирует код, превращая delete[] в delete когда надо.

Хмм... А можно источник?
"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"
Re[6]: delete и delete[ ]
От: Critical Error ICQ: 123736611
Дата: 30.01.07 09:52
Оценка: :)
Здравствуйте, vasmann, Вы писали:

V>А как Вы себе представляете унифицированный опереатор new и delete?

V>Ведь если вы просто выделяете память то Вам надо просто вернуть указатель, а если блок памяти (читай динамический массив) то помимо указателя нужно выделить еще как минимум 4 байта для храниения кол-ва обьектов. А отсюда вытекает что если вы хотите унифицироавнные опереаторы — то получите всегда дополнительные 4 байта плюс не нужные оператор цикла (даже для одного элемента) — а это НИКОМУ не нада. И действительно что мешает писать правильно? И еще: лучше использовать std::vector — все вопрсы решены. Ну или либу boost (www.boost.org).

4 байта хранить совершенно не нужно, массивы, выделенные по new[] и malloc()-ом ничем не отличаются, просто в случае new[] вызовутся конструкторы для всех объектов. Если приспичило узнать количество элементов в массиве можно это сделать так: size_t nn = memory_allocated / sizeof(Object);
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: delete и delete[ ]
От: Critical Error ICQ: 123736611
Дата: 30.01.07 10:01
Оценка: :)
Здравствуйте, Zigmar, Вы писали:

Z>Ты забыл добавить "В компиляторе A, версии B, с опциями C, на платформе D". Тогда только можно было бы говорить о верности такого предположения.

Если бы я был создателем компиляторов, то я бы сделал именно так как описал. Или я чегото недопонимаю, я чегото не учел?

Z>Т.е. ты предлагаешь вместо того, чтоб писать корректный код, полагаться на имлементацию UB в конкретном компиляторе. Отличное, решение, да.

Z>Кстати, ситуации, когда "не уверен как выделялся объект" — не должно быть в принципе.

Z>Ничего страшно, ну разве что упадёт разок другой или диск отформатирует... UB и в Африке UB.


Ну ты сам подумай, как вызов delete[] на корректной области памяти может вызвать крах приложения? Лично у меня фантазии не хватает.

CE>>Тем более, кто компилятор сам иногда оптимизирует код, превращая delete[] в delete когда надо.

Z>Хмм... А можно источник?

Я сам не уверен, но это вполне логично. Это не трудно проверить эксперементально если тебя так уж задевают лишние пара тактов процессора: скомпилируй приложение с оптимизацией и посмотри ассемблерный код под отладчиком, либо сгенерировав дамп во время компиляции.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: delete и delete[ ]
От: LaPerouse  
Дата: 30.01.07 10:40
Оценка: :)
Здравствуйте, Critical Error, Вы писали:

CE>Здравствуйте, CompileError, Вы писали:


CE>>Правда ли, что если создать массив объектов, то при его удалении с помощью операции delete не будут вызваны деструкторы для каждого из элементов массива (обязательно надо использовать delete[ ] )?


CE>При удалении массива объектов с помощью delete[] сначала запускается цикл, который тупо берет адрес массива, затем вызывает деструктор, прибавляет к адресу размер элемента и гоняет цикл пока не выйдет за границу массива.


CE>Так что создан массив с помощью new[] или просто malloc()-ом не важно. Поведение delete и delete[] довольно предсказуемо. Поэтому когда не уверен будет ли в точке удаления один объект или массив объектов, лучше применять delete[]. Если там один элемент — ничего страшного, вызовется деструктор один раз, потеряешь только пару машинных тактов на обработку цикла. Зато никакой неопределенности не будет. Тем более, кто компилятор сам иногда оптимизирует код, превращая delete[] в delete когда надо.



Если массив создается malloc'ом, я не думаю, что его размер идет вместе с ним. В каких-то компиляторах это может быть реализовано, полагаться на это не стоит.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[3]: delete и delete[ ]
От: Critical Error ICQ: 123736611
Дата: 30.01.07 10:50
Оценка:
Здравствуйте, LaPerouse, Вы писали:

LP>Если массив создается malloc'ом, я не думаю, что его размер идет вместе с ним. В каких-то компиляторах это может быть реализовано, полагаться на это не стоит.


Размер массива идет с массивом ВСЕГДА и находится он перед адресом, который возвращает malloc. Кстати говоря new и new[] реализованы с применением того же самого malloc-а.

Правда есть еще один вариант, когда размер не идет с массивом, но он всеравно известен из како-нибудь таблицы менаджера памяти. Иначе откуда free() будет знать сколько памяти необходимо освободить? Ну, такой вариант маловероятен. Если интересно, можно залезть в исходники free() и глянуть как там все устроено.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: delete и delete[ ]
От: Left2 Украина  
Дата: 30.01.07 10:59
Оценка:
CE>При удалении массива объектов с помощью delete[] сначала запускается цикл, который тупо берет адрес массива, затем вызывает деструктор, прибавляет к адресу размер элемента и гоняет цикл пока не выйдет за границу массива.

CE>Так что создан массив с помощью new[] или просто malloc()-ом не важно. Поведение delete и delete[] довольно предсказуемо. Поэтому когда не уверен будет ли в точке удаления один объект или массив объектов, лучше применять delete[]. Если там один элемент — ничего страшного, вызовется деструктор один раз, потеряешь только пару машинных тактов на обработку цикла. Зато никакой неопределенности не будет. Тем более, кто компилятор сам иногда оптимизирует код, превращая delete[] в delete когда надо.


Категорически против того чтобы кто-либо следовал таким советам. Даже если это будет работать на каком-то конкретном компиляторе (не факт что это будет работать для следующей версии) ситуация с перекрытыми операторами new и new[] в каком-то конкретном классе или глобально вызовет, скорее всего, крах программы. Ну и действительно согласен с Zigmar — ситуация "не уверен как выделялся объект" — это уже само по себе признак программирования "на коленке".
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: delete и delete[ ]
От: Critical Error ICQ: 123736611
Дата: 30.01.07 11:29
Оценка:
Здравствуйте, Left2, Вы писали:

L>Категорически против того чтобы кто-либо следовал таким советам. Даже если это будет работать на каком-то конкретном компиляторе (не факт что это будет работать для следующей версии) ситуация с перекрытыми операторами new и new[] в каком-то конкретном классе или глобально вызовет, скорее всего, крах программы. Ну и действительно согласен с Zigmar — ситуация "не уверен как выделялся объект" — это уже само по себе признак программирования "на коленке".


А я говорю, что это хорошо? Я объяснил как работает delete[] и только. Выводы делайте сами, вы же программисты.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: delete и delete[ ]
От: Left2 Украина  
Дата: 30.01.07 11:36
Оценка: +1
L>>Категорически против того чтобы кто-либо следовал таким советам. Даже если это будет работать на каком-то конкретном компиляторе (не факт что это будет работать для следующей версии) ситуация с перекрытыми операторами new и new[] в каком-то конкретном классе или глобально вызовет, скорее всего, крах программы. Ну и действительно согласен с Zigmar — ситуация "не уверен как выделялся объект" — это уже само по себе признак программирования "на коленке".

CE>А я говорю, что это хорошо? Я объяснил как работает delete[] и только. Выводы делайте сами, вы же программисты.

Ты предположил как работает delete[]. И посоветовал воспользоваться этим предположением. Я категорически против использования таких советов, о чём и написал. Ну и опять же — по твоему сообщению нельзя понять насколько серьёзно ты это предлагаешь. По нику в форуме никто не может определить уровень твоей квалификации. В итоге запросто человек неопытный может принять этот совет за чистую монету и использовать такое извращение в "боевом" коде.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: delete и delete[ ]
От: . Великобритания  
Дата: 30.01.07 11:45
Оценка: +1
Critical Error wrote:

> элементов в массиве можно это сделать так: size_t nn = memory_allocated

> / sizeof(Object);
memory_allocated может быть больше запрошенного (например, может быть необходимо для выравнивания).
В общем объединение new и new[] накладывает некоторые ограничения на устройство менеджера памяти.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: delete и delete[ ]
От: Zigmar Израиль  
Дата: 30.01.07 12:10
Оценка:
Здравствуйте, Critical Error, Вы писали:
CE>Размер массива идет с массивом ВСЕГДА и находится он перед адресом, который возвращает malloc.
Что "всегда" — это бред. Это зависит от конкретной реализации. К тому-же далеко не каждому подходит реализация с оверхеадом в sizeof(size_t) байт на блок.

CE>Правда есть еще один вариант, когда размер не идет с массивом, но он всеравно известен из како-нибудь таблицы менаджера памяти. Иначе откуда free() будет знать сколько памяти необходимо освободить?

Я могу предположить, что ты не очень знаком с аллокаторами, потому что редко когда освобождение/выделение сводится к "взять/положить N байт". Аллокаторы по любому поддерживают сложные структуры данных, которые нужны чтобы удовлетворить запросы с достаточной скоростью и не допускать фрагментации. Кстати, из нескольких алгоритмов которые я знаю (а их очень много), не одному не нужно хранить размер блока вообще, не с указателем, не отдельно. Да иногда нужно хранить дополнительную информацию, но это обычно не размер.

CE>Ну, такой вариант маловероятен. Если интересно, можно залезть в исходники free() и глянуть как там все устроено.

Можно конечно, хотя то что ты там обнаружишь, не будет говорить не о чём, кроме конкретной имплементации. Посмотри вот например:
malloc.c (avr-libc-1.2.6)
"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"
Re[2]: delete и delete[ ]
От: Tonal- Россия www.promsoft.ru
Дата: 30.01.07 12:32
Оценка:
Кроме возражений, которые тебе уже написали, хочу заметить, что в предложенной тобой реализации delete[] есть ошибочка:
Для корректной работы описанного алгоритма, надо в заголовке болка всегда сохранять 2 числа — общую длинну блока и либо размер элемента, либо их количество, можно ещё размер элемента и количество.
Причём, если мы стремимся, добиться одинаковой работы delete и delete[], надо, чтобы заголовок был одинаковый для new и new[].
Да, ещё указатель на деструктор в этом заголовке сохранить — и совсем всё ... будет.
Re[4]: delete и delete[ ]
От: igna Россия  
Дата: 30.01.07 12:44
Оценка:
Здравствуйте, Critical Error, Вы писали:

CE>Ну ты сам подумай, как вызов delete[] на корректной области памяти может вызвать крах приложения? Лично у меня фантазии не хватает.


Ну, например, перед первым элементом массива может храниться его размер. При попытке при помощи delete[] удалить не массив, а отдельный объект, за размер будет принято кое-что другое...
Re[5]: delete и delete[ ]
От: Critical Error ICQ: 123736611
Дата: 30.01.07 13:23
Оценка: -1
Здравствуйте, igna, Вы писали:

I>Ну, например, перед первым элементом массива может храниться его размер. При попытке при помощи delete[] удалить не массив, а отдельный объект, за размер будет принято кое-что другое...


Еще раз повторяю, что менаджер памяти перед любым куском памяти будь то массив или один элемент хранит размер этого массива или этого элемента. Никаких дополнительных данных нет и не нужны они. Поэтому вызов delete и delete[] для одного объекта абсолютно ничем не отличаются. Я както непонятно выражаюсь?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: delete и delete[ ]
От: Zigmar Израиль  
Дата: 30.01.07 13:43
Оценка:
Здравствуйте, Critical Error, Вы писали:

CE>Еще раз повторяю, что менаджер памяти перед любым куском памяти будь то массив или один элемент хранит размер этого массива или этого элемента. Никаких дополнительных данных нет и не нужны они. Поэтому вызов delete и delete[] для одного объекта абсолютно ничем не отличаются. Я както непонятно выражаюсь?

Понятно но неправильно. Я не вижу смысла продолжать спор, если ты всё равно никого не хочешь слушать.
"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"
Re[4]: delete и delete[ ]
От: vasmann  
Дата: 30.01.07 14:49
Оценка:
Здравствуйте, Critical Error, Вы писали:

CE>Здравствуйте, LaPerouse, Вы писали:


LP>>Если массив создается malloc'ом, я не думаю, что его размер идет вместе с ним. В каких-то компиляторах это может быть реализовано, полагаться на это не стоит.


CE>Размер массива идет с массивом ВСЕГДА и находится он перед адресом, который возвращает malloc. Кстати говоря new и new[] реализованы с применением того же самого malloc-а.


CE>Правда есть еще один вариант, когда размер не идет с массивом, но он всеравно известен из како-нибудь таблицы менаджера памяти. Иначе откуда free() будет знать сколько памяти необходимо освободить? Ну, такой вариант маловероятен. Если интересно, можно залезть в исходники free() и глянуть как там все устроено.


Простой вопрос:
Почему в библитотек boost (www.boost.org) реализованы 2 разных подтипа референс каунтинг классов
shared_ptr/scoped_ptr и shared_array/scoped_array?


В общем спор глупый, ибо будь все так просто — был бы только один оператор new (new[]) и соответсенно delete(delete []).

А также напишите маленькую прогу, в которой память выделите через new а удалите через delete [] (в цикле эти действия) — у меня валится, ставлю просто delete — все пучком.
Re[3]: delete и delete[ ]
От: Critical Error ICQ: 123736611
Дата: 30.01.07 14:55
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Кроме возражений, которые тебе уже написали, хочу заметить, что в предложенной тобой реализации delete[] есть ошибочка:

T>Для корректной работы описанного алгоритма, надо в заголовке болка всегда сохранять 2 числа — общую длинну блока и либо размер элемента, либо их количество, можно ещё размер элемента и количество.
T>Причём, если мы стремимся, добиться одинаковой работы delete и delete[], надо, чтобы заголовок был одинаковый для new и new[].
T>Да, ещё указатель на деструктор в этом заголовке сохранить — и совсем всё ... будет.

Не путайте пожалуйста реализацию delete с реализацией менаджера памяти. Я уже говорил, что delete[] в конце вызывает free (или что-то в этом роде зависящее от реализации) для освобождения памяти. А уж что там менаджер памяти делать будет нас уже не касается.

Я тут с перепугу от того, что вы мне рассказали, решил залезть в сырцы менаджера памяти у MSVC7.1. Я действительно ошибся, сказав, что там якобы размер хранится. Оказалось не размер, а указатель на дескриптор блока. Ну а сам дескриптор не хранит размер блока. В общем как это все работает я дальше разбираться не стал потому как к делу не относится. У меня так вообще компилятор malloc и free в HeapAlloc и HeapFree скомпилировал, то есть crt-шный менаджер не использовал.

Я думаю примерно то же самое и в gcc и в других реализациях (поправьте если я ошибаюсь).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: delete и delete[ ]
От: igna Россия  
Дата: 30.01.07 16:32
Оценка:
Здравствуйте, Critical Error, Вы писали:

CE>Еще раз повторяю, что менаджер памяти перед любым куском памяти будь то массив или один элемент хранит размер этого массива или этого элемента. Никаких дополнительных данных нет и не нужны они. Поэтому вызов delete и delete[] для одного объекта абсолютно ничем не отличаются. Я както непонятно выражаюсь?


Прошу прощения, под размером массива я имел в виду количество его элементов. (Размер в байтах тоже хранится, но и в самом деле независимо от того, массив это или нет.) А ты сразу по морде...

15.6.1 Array Allocation [hier.array]

The operator new() and operator delete() functions allow a user to take over allocation and
deallocation of individual objects; operator new[]() and operator delete[]() serve exactly the
same role for the allocation and deallocation of arrays. For example:

class Employee {
public :
    void* operator new[](size_ t);
    void operator delete[](void*, size_ t);
    // ...
};

void f(int s)
{
    Employee* p = new Employee[s];
    // ...
    delete[] p ;
}


Here, the memory needed will be obtained by a call,

    Employee::operator new[](sizeof(Employee) * s + delta)


where delta is some minimal implementation-defined overhead, and released by a call:

    Employee::operator delete[](p, s * sizeof(Employee) + delta)


The number of elements (s) is ‘‘remembered’’ by the system.

(Bjarne Stroustrup, The C++ Programming Language, Third Edition)

Re[6]: delete и delete[ ]
От: igna Россия  
Дата: 30.01.07 16:53
Оценка:
Здравствуйте, Critical Error, Вы писали:

CE>Еще раз повторяю, что менаджер памяти перед любым куском памяти будь то массив или один элемент хранит размер этого массива или этого элемента. Никаких дополнительных данных нет и не нужны они. Поэтому вызов delete и delete[] для одного объекта абсолютно ничем не отличаются. Я както непонятно выражаюсь?


Вот тебе еще из стандарта:

5.3.5 Delete [expr.delete]

1 The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression.
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
The first alternative is for non-array objects, and the second is for arrays. The operand shall have a pointer
type, or a class type having a single conversion function (12.3.2) to a pointer type. The result has type
void.

2 If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned
conversion function, and the converted operand is used in place of the original operand for the remainder of
this section. In either alternative, if the value of the operand of delete is the null pointer the operation
has no effect. In the first alternative (delete object), the value of the operand of delete shall be a pointer
to a non-array object or a pointer to a sub-object (1.8) representing a base class of such an object (clause
10). If not, the behavior is undefined. In the second alternative (delete array), the value of the operand of
delete shall be the pointer value which resulted from a previous array new-expression. If not, the
behavior is undefined.

Re[7]: delete и delete[ ]
От: MikelSV http://www.centerix.ru
Дата: 30.01.07 17:04
Оценка: :)
Когда массив стрингов созданный таким методом не захотел умирать спокойно я, недолго думая, сделал так:

void*GetBuffer(int size){
void *buf=new char[size];
memset(buf, 0, size);
return buf;
}

в int запихнул размер массива.
а в конце проходился по нему убивая его обьекты.


Может не совсем правильное, но быстрое решение задачи
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re: delete и delete[ ]
От: CompileError  
Дата: 30.01.07 21:27
Оценка:
Короче, окончательно затуманили мой мозг! Спасибо...
Re[6]: delete и delete[ ]
От: Андрей Тарасевич Беларусь  
Дата: 30.01.07 23:24
Оценка:
Здравствуйте, Critical Error, Вы писали:

I>>Ну, например, перед первым элементом массива может храниться его размер. При попытке при помощи delete[] удалить не массив, а отдельный объект, за размер будет принято кое-что другое...


CE>Еще раз повторяю, что менаджер памяти перед любым куском памяти будь то массив или один элемент хранит размер этого массива или этого элемента. Никаких дополнительных данных нет и не нужны они. Поэтому вызов delete и delete[] для одного объекта абсолютно ничем не отличаются. Я както непонятно выражаюсь?


Понятно. Но не верно. Дополнительные данные нужны.

Да менежер памяти перед любым куском памяти хранит размер этого куска. Но это не "размер массива". И размер массива из размера куска вывести однозначно в общем случае нельзя. Если разделить размер куска на размер элемента массива, то результат получится в общем случае больше, чем размер указанный в 'new[]'. Поэтому, в случае необходимости выозва деструкторов по 'delete[]', в начале блока памяти, выделенном по 'new[]' хранятся два размера: во-первых, хранится размер сырого блока (тот самый размер, о котором ты говоришь), во-вторых, хранится еще и размер массива, указывавшийся в 'new[]' при выделении.

Вызов 'delete' и 'delete[]' для одного объекта будут совпадать только в том случае, если это объект не имеет деструктора (или имеет тривиальный деструктор). А вот если окажется что этот объект имеет нетривиальный деструктор, то вызовы 'delete' и 'delete[]' для него будут отличаться. И отличаться сильно.

Все вышесказанное является деталями "традиционной" реализации (MSVC 6, GCC). В конкретных реализациях все может быть по-другому.

См. также здесь

http://rsdn.ru/Forum/Message.aspx?mid=1693105&amp;only=1
Автор: Андрей Тарасевич
Дата: 22.02.06
Best regards,
Андрей Тарасевич
Re[2]: delete и delete[ ]
От: Tonal- Россия www.promsoft.ru
Дата: 31.01.07 08:57
Оценка:
Здравствуйте, CompileError, Вы писали:
CE>Короче, окончательно затуманили мой мозг! Спасибо...
Кароче всё просто: если ты создал объект с помощью new, то удалять его надо с помощью delete.
А если создал массив объектов с помощью new[], то удалять его надо с помощью delete[].
Если ты сделаешь не так, никто не гарантирует как и когда упадёт твоя программа.
Что конкретно произойдёт в случае той или другой ошибки, сильно зависит от операционки, компилятора, опций оного, фазы луны и температуры за бортом.

Ну и по общим принципам кодирования/дизайна — смешивть объект и массив объектов плохой, негодный дизайн.
Re[7]: delete и delete[ ]
От: Кодт Россия  
Дата: 31.01.07 11:38
Оценка: +1
Здравствуйте, LaPerouse, Вы писали:

LP>Если я не ошибаюсь, размер массива и так хранится, при условии, что массив расположен в динамической памяти (т е в случае, если delete вообще применим).


Внутреннее устройство кучи — личное дело конкретной реализации.
Возможны варианты, когда не нужно хранить размер занятого блока рядом с блоком. Например, когда размер блока определяется прямо из адреса (есть пулы блоков разного размера).

К тому же, для менеджера кучи нужно знать именно размер блока, который кратен величине гранулярности. Например, для небольших блоков — 16 байт, а для больших — 16 кбайт.
Количество объектов, помещающихся в блок или реально в нём размещённых — это разные величины

LP>Что касается цикла по объектам, то его можно избежать, если трактовать delete именно как уничтожение массива. Как же тогда уничтожить первый элемент? Просто — явным обращением [index], т е это должна быть забота компилятора.


Да пожалуйста. Всегда выделяй память через new[] и грохай через delete[]. И только там, где тебе заведомо известно, что это один элемент, и ты хочешь сэкономить на спичках — пользуйся new/delete.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[8]: delete и delete[ ]
От: Tonal- Россия www.promsoft.ru
Дата: 31.01.07 12:29
Оценка: 28 (2)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, LaPerouse, Вы писали:

LP>>Что касается цикла по объектам, то его можно избежать, если трактовать delete именно как уничтожение массива. Как же тогда уничтожить первый элемент? Просто — явным обращением [index], т е это должна быть забота компилятора.
К>Да пожалуйста. Всегда выделяй память через new[] и грохай через delete[]. И только там, где тебе заведомо известно, что это один элемент, и ты хочешь сэкономить на спичках — пользуйся new/delete.
Только один момент — при этом нужно распрощаться с удалением потомка через указатель на предка.
Ведь только delete учитывает динамический тип, а delete[] использует статический.
Этот момент как-то обошли в данном обсуждении.
Re[9]: delete и delete[ ]
От: Кодт Россия  
Дата: 31.01.07 13:32
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Только один момент — при этом нужно распрощаться с удалением потомка через указатель на предка.

T>Ведь только delete учитывает динамический тип, а delete[] использует статический.
T>Этот момент как-то обошли в данном обсуждении.

Опаньки, и действительно!
А с другой стороны, динамический массив потомков — хоть ты его new[], хоть как угодно создай — будет статически несовместим с предками. Потому что адресная арифметика уплывёт.
Следовательно, нужно или избегать таких ситуаций, или инкапсулировать. Ну а раз инкапсуляция, то можно и placement new/delete задействовать — как это делает тот же vector.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: delete и delete[ ]
От: Sm0ke Россия ksi
Дата: 31.01.07 14:22
Оценка:
А если так?
typedef
  int
  some_type[10];

some_type * h= new some_type; /* вроде это преобразуется в: new int[10] */
delete h;
Re[4]: delete и delete[ ]
От: Tonal- Россия www.promsoft.ru
Дата: 01.02.07 06:14
Оценка:
Здравствуйте, Sm0ke, Вы писали:
S>А если так?
S>
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[] выглядело бы естественно.
Или в структурку завернуть:
struct some_type {
  int arr[10];
  int& operator[](int i){return *(arr + i);}
}


Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено.
Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло.
Например:
int arr[10];
int[] elt = arr + 3; //Ok
int[] elt = &arr[3]; //Ok
elt++; //ok
int*  obj = arr + 3; //err
int*  obj = static_cast<int*>(arr + 3); //Ok
int* obj = &arr[3]; //err
int* obj = static_cast<int*>(&arr[3]);
obj++ //err
Re[5]: delete и delete[ ]
От: Erop Россия  
Дата: 03.02.07 13:18
Оценка:
Здравствуйте, Left2, Вы писали:

CE>>А я говорю, что это хорошо? Я объяснил как работает delete[] и только. Выводы делайте сами, вы же программисты.

L>Ты предположил как работает delete[]. И посоветовал воспользоваться этим предположением. Я категорически против использования таких советов, о чём и написал. Ну и опять же — по твоему сообщению нельзя понять насколько серьёзно ты это предлагаешь. По нику в форуме никто не может определить уровень твоей квалификации. В итоге запросто человек неопытный может принять этот совет за чистую монету и использовать такое извращение в "боевом" коде.

Ну там же написано, что совет от критической ошибки
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: delete и delete[ ]
От: Ovl Россия  
Дата: 05.02.07 16:14
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Tonal-, Вы писали:


T>>Только один момент — при этом нужно распрощаться с удалением потомка через указатель на предка.

T>>Ведь только delete учитывает динамический тип, а delete[] использует статический.
T>>Этот момент как-то обошли в данном обсуждении.

К>Опаньки, и действительно!

К>А с другой стороны, динамический массив потомков — хоть ты его new[], хоть как угодно создай — будет статически несовместим с предками. Потому что адресная арифметика уплывёт.
К>Следовательно, нужно или избегать таких ситуаций, или инкапсулировать. Ну а раз инкапсуляция, то можно и placement new/delete задействовать — как это делает тот же vector.

стало интересно, пытался сделать тест, получилось

struct Test1 {
    Test1() { printf("Test1\r\n"); }
    virtual ~Test1() { printf("~Test1\r\n"); }

    virtual void CallMe() = 0;
};

struct Test2 : public Test1 {
    int t;

    void CallMe() {};

    Test2() { printf("Test2\r\n"); }
    virtual ~Test2() { printf("~Test2\r\n"); }
};

Test1* AllocateArray() {
    return new Test2[2];
}

void DeleteArray(Test1* arr) {
    arr[0].CallMe();
    arr[1].CallMe(); //vfpt безнадежно испорчен :(
    delete[] arr;
}

void main() {
    DeleteArray(AllocateArray());
}
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[5]: placement new/delete function-wrapper
От: Vain Россия google.ru
Дата: 05.02.07 18:33
Оценка:
Здравствуйте, 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>struct some_type {
T>  int arr[10];
T>  int& operator[](int i){return *(arr + i);}
T>}
T>


T>Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено.

T>Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло.
T>Например:
T>
T>int arr[10];
T>int[] elt = arr + 3; //Ok
T>int[] elt = &arr[3]; //Ok
T>elt++; //ok
T>int*  obj = arr + 3; //err
T>int*  obj = static_cast<int*>(arr + 3); //Ok
T>int* obj = &arr[3]; //err
T>int* obj = static_cast<int*>(&arr[3]);
T>obj++ //err
T>


А вот это надёжно?
#include <stdio.h>
#include <new.h>

struct TEST {
  TEST() {
    printf(__FUNCSIG__ "\n");
  }
  ~TEST() {
    printf(__FUNCSIG__ "\n");
  }
};

template<class T> class DtorClassWrapper {
  T Wrappee;
  template<class AS> friend void DestructMeAs(void* pObj);
};

template<class AS> void ConstructMeAs(void* pObj) {
  ::new (pObj) AS;
}
template<class AS> void DestructMeAs(void* pObj) {
  //reinterpret_cast<AS*>(pObj)->AS::~AS(); //Оппа, не сработало :(
  //::delete(pObj,pObj); //И подавно, зачем тогда размещающий delete нужен? :(

  //Дубовая заплатка :)
  typedef DtorClassWrapper<AS> DTOR_TYPE;
  reinterpret_cast<DTOR_TYPE*>(pObj)->DTOR_TYPE::~DTOR_TYPE();
};

int main() {
  typedef TEST ARR[2];
  //T_ALIGNED_STORAGE<ARR,2,1> buf;
  char buf[sizeof(ARR)]; //Чхали на выравнивание..
  ConstructMeAs<ARR>(buf);
  //blabla..
  DestructMeAs<ARR>(buf);
}
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[11]: delete и delete[ ]
От: Vain Россия google.ru
Дата: 05.02.07 19:54
Оценка:
Здравствуйте, Ovl, Вы писали:

Ovl>стало интересно, пытался сделать тест, получилось

Ovl>
Ovl>struct Test1 {
Ovl>    Test1() { printf("Test1\r\n"); }
Ovl>    virtual ~Test1() { printf("~Test1\r\n"); }

Ovl>    virtual void CallMe() = 0;
Ovl>};

Ovl>struct Test2 : public Test1 {
Ovl>    int t;

Ovl>    void CallMe() {};

Ovl>    Test2() { printf("Test2\r\n"); }
Ovl>    virtual ~Test2() { printf("~Test2\r\n"); }
Ovl>};

Ovl>Test1* AllocateArray() {
Ovl>    return new Test2[2];
Ovl>}

Ovl>void DeleteArray(Test1* arr) {
Ovl>    arr[0].CallMe();
Ovl>    arr[1].CallMe(); //vfpt безнадежно испорчен :(
Ovl>    delete[] arr;
Ovl>}

Ovl>void main() {
Ovl>    DeleteArray(AllocateArray());
Ovl>}
Ovl>


Тоже пытался, но результаты честно говоря очень странные
class VOID_TYPE {};
typedef struct VTableTag* VTable;

template<class T> const VTable* GetVTablePointer() {
  static T dummy = VOID_TYPE(); //Avoiding manual-forced vfptr initializing
  return reinterpret_cast<VTable*>(*reinterpret_cast<unsigned int*>(&dummy));
}
template<class T> void SetVTablePointer(T* pObj) {
  *reinterpret_cast<const VTable**>(pObj) = GetVTablePointer<T>();
}

struct Test1 {
  Test1() { SetVTablePointer(this); } //Not needed for test, just in case
  Test1(VOID_TYPE) { } //Void constructor
  virtual ~Test1() { printf(__FUNCSIG__ "\n"); }
  virtual void CallMe() { printf(__FUNCSIG__ "\n"); }
};

struct Test2 : public Test1 {
  Test2() { SetVTablePointer(this); } //Manual-forced vfptr initializing
  Test2(VOID_TYPE) : Test1(VOID_TYPE()) { } //Void constructor
  virtual ~Test2() { printf(__FUNCSIG__ "\n"); }
  void CallMe() { printf(__FUNCSIG__ "\n"); }; //Cheking virtual function
};

Test1* AllocateArray() {
  return new Test2[2];
}

void DeleteArray(Test1* arr) {
  arr[0].CallMe();
  arr[1].CallMe(); //Works..
  delete[] arr; //Cleaning..
}

int main() {
  DeleteArray(AllocateArray());
  return 0;
}


msvc2005+sp1 (/w debugger):

void __thiscall Test2::CallMe(void)
void __thiscall Test2::CallMe(void)
__thiscall Test2::~Test2(void)
__thiscall Test1::~Test1(void)
__thiscall Test2::~Test2(void)
__thiscall Test1::~Test1(void)


msvc2005+sp1 (w/o debugger):

void __thiscall Test2::CallMe(void)
void __thiscall Test2::CallMe(void)
__thiscall Test2::~Test2(void)
__thiscall Test1::~Test1(void)
__thiscall Test2::~Test2(void)
__thiscall Test1::~Test1(void)
__thiscall Test2::~Test2(void)
__thiscall Test1::~Test1(void)
__thiscall Test1::~Test1(void)

Непонятно откуда вызвалось

comeau 4.3.3 (MODE:non-strict warnings microsoft C++)
void Test2::CallMe()
void Test2::CallMe()
Test1::~Test1()
Test1::~Test1()
Test2::~Test2()
Test1::~Test1()
Test1::~Test1()

Оригинально-симметрично..
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[6]: placement new/delete function-wrapper
От: Vain Россия google.ru
Дата: 08.02.07 03:33
Оценка:
Здравствуйте, 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>>struct some_type {
T>>  int arr[10];
T>>  int& operator[](int i){return *(arr + i);}
T>>}
T>>


T>>Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено.

T>>Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло.
T>>Например:
T>>
T>>int arr[10];
T>>int[] elt = arr + 3; //Ok
T>>int[] elt = &arr[3]; //Ok
T>>elt++; //ok
T>>int*  obj = arr + 3; //err
T>>int*  obj = static_cast<int*>(arr + 3); //Ok
T>>int* obj = &arr[3]; //err
T>>int* obj = static_cast<int*>(&arr[3]);
T>>obj++ //err
T>>


V>А вот это надёжно?

V>
V>#include <stdio.h>
V>#include <new.h>

V>struct TEST {
V>  TEST() {
V>    printf(__FUNCSIG__ "\n");
V>  }
V>  ~TEST() {
V>    printf(__FUNCSIG__ "\n");
V>  }
V>};

V>template<class T> class DtorClassWrapper {
V>  T Wrappee;
V>  template<class AS> friend void DestructMeAs(void* pObj);
V>};

V>template<class AS> void ConstructMeAs(void* pObj) {
V>  ::new (pObj) AS;
V>}
V>template<class AS> void DestructMeAs(void* pObj) {
V>  //reinterpret_cast<AS*>(pObj)->AS::~AS(); //Оппа, не сработало :(
V>  //::delete(pObj,pObj); //И подавно, зачем тогда размещающий delete нужен? :(

V>  //Дубовая заплатка :)
V>  typedef DtorClassWrapper<AS> DTOR_TYPE;
V>  reinterpret_cast<DTOR_TYPE*>(pObj)->DTOR_TYPE::~DTOR_TYPE();
V>};

V>int main() {
V>  typedef TEST ARR[2];
V>  //T_ALIGNED_STORAGE<ARR,2,1> buf;
V>  char buf[sizeof(ARR)]; //Чхали на выравнивание..
V>  ConstructMeAs<ARR>(buf);
V>  //blabla..
V>  DestructMeAs<ARR>(buf);
V>}
V>

up
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[12]: delete и delete[ ]
От: Vain Россия google.ru
Дата: 08.02.07 03:34
Оценка:
Здравствуйте, Vain, Вы писали:

V>Здравствуйте, Ovl, Вы писали:


Ovl>>стало интересно, пытался сделать тест, получилось

Ovl>>
Ovl>>struct Test1 {
Ovl>>    Test1() { printf("Test1\r\n"); }
Ovl>>    virtual ~Test1() { printf("~Test1\r\n"); }

Ovl>>    virtual void CallMe() = 0;
Ovl>>};

Ovl>>struct Test2 : public Test1 {
Ovl>>    int t;

Ovl>>    void CallMe() {};

Ovl>>    Test2() { printf("Test2\r\n"); }
Ovl>>    virtual ~Test2() { printf("~Test2\r\n"); }
Ovl>>};

Ovl>>Test1* AllocateArray() {
Ovl>>    return new Test2[2];
Ovl>>}

Ovl>>void DeleteArray(Test1* arr) {
Ovl>>    arr[0].CallMe();
Ovl>>    arr[1].CallMe(); //vfpt безнадежно испорчен :(
Ovl>>    delete[] arr;
Ovl>>}

Ovl>>void main() {
Ovl>>    DeleteArray(AllocateArray());
Ovl>>}
Ovl>>


V>Тоже пытался, но результаты честно говоря очень странные

V>
V>class VOID_TYPE {};
V>typedef struct VTableTag* VTable;

V>template<class T> const VTable* GetVTablePointer() {
V>  static T dummy = VOID_TYPE(); //Avoiding manual-forced vfptr initializing
V>  return reinterpret_cast<VTable*>(*reinterpret_cast<unsigned int*>(&dummy));
V>}
V>template<class T> void SetVTablePointer(T* pObj) {
V>  *reinterpret_cast<const VTable**>(pObj) = GetVTablePointer<T>();
V>}

V>struct Test1 {
V>  Test1() { SetVTablePointer(this); } //Not needed for test, just in case
V>  Test1(VOID_TYPE) { } //Void constructor
V>  virtual ~Test1() { printf(__FUNCSIG__ "\n"); }
V>  virtual void CallMe() { printf(__FUNCSIG__ "\n"); }
V>};

V>struct Test2 : public Test1 {
V>  Test2() { SetVTablePointer(this); } //Manual-forced vfptr initializing
V>  Test2(VOID_TYPE) : Test1(VOID_TYPE()) { } //Void constructor
V>  virtual ~Test2() { printf(__FUNCSIG__ "\n"); }
V>  void CallMe() { printf(__FUNCSIG__ "\n"); }; //Cheking virtual function
V>};

V>Test1* AllocateArray() {
V>  return new Test2[2];
V>}

V>void DeleteArray(Test1* arr) {
V>  arr[0].CallMe();
V>  arr[1].CallMe(); //Works..
V>  delete[] arr; //Cleaning..
V>}

V>int main() {
V>  DeleteArray(AllocateArray());
V>  return 0;
V>}
V>


V>msvc2005+sp1 (/w debugger):

V>

V>void __thiscall Test2::CallMe(void)
V>void __thiscall Test2::CallMe(void)
V>__thiscall Test2::~Test2(void)
V>__thiscall Test1::~Test1(void)
V>__thiscall Test2::~Test2(void)
V>__thiscall Test1::~Test1(void)


V>msvc2005+sp1 (w/o debugger):

V>

V>void __thiscall Test2::CallMe(void)
V>void __thiscall Test2::CallMe(void)
V>__thiscall Test2::~Test2(void)
V>__thiscall Test1::~Test1(void)
V>__thiscall Test2::~Test2(void)
V>__thiscall Test1::~Test1(void)
V>__thiscall Test2::~Test2(void)
V>__thiscall Test1::~Test1(void)
V>__thiscall Test1::~Test1(void)

V>Непонятно откуда вызвалось

V>comeau 4.3.3 (MODE:non-strict warnings microsoft C++)

V>
V>void Test2::CallMe()
V>void Test2::CallMe()
V>Test1::~Test1()
V>Test1::~Test1()
V>Test2::~Test2()
V>Test1::~Test1()
V>Test1::~Test1()
V>

V>Оригинально-симметрично..
up
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[5]: delete и delete[ ]
От: Programador  
Дата: 07.03.07 16:30
Оценка: -1
Здравствуйте, Tonal-, Вы писали:

T>Вообще, этот класс ошибок связан с тем, что указатель совмещает две разные роли, а синтаксически это никак не отражено.

T>Вот если бы указатель на элемент массива имел тип отличный от указателя на одиночный объект, подобных ошибок возникнуть бы не могло.

По значанию различимы
    y=new A[1];
    x=new A();
    y=new A[1];
    x=new A();
    y=new A[1];
    x=new A();
    x=new A();
    x=new A();
    x=new A();
    y=new A[1];
    y=new A[1];
    y=new A[1];
    y=new A[1];

в отладчике оверхеад видно. посдедняя цифра в [] не 0.

Здравствуйте, Кодт, Вы писали:

К>Да пожалуйста. Всегда выделяй память через new[] и грохай через delete[]. И только там, где тебе заведомо известно, что это один элемент, и ты хочешь сэкономить на спичках — пользуйся new/delete.


есть еще new A() и new A(орлор,олдол,йцуцй)

так что для автоматического удаления по выходу из контекста (тоесть ретурн далеко, а то и не один) велосипед нужен или 2 отдельных.

template <class T >struct autoVelo
{ T* privatPtr;
  inline autoVelo(T*p){privatPtr=p;}
  inline operator T*(){return privatPtr;} 
  inline ~autoVelo()
   { if(privatPtr)
     if(0xF&(unsigned)(void*)privatPtr)
       delete[] privatPtr;
     else
        delete privatPtr;     
   }
  private:
  operator =( autoVelo<T>){}
};


..............
    autoVelo<A> a0(new A [1] );
    autoVelo<A> a1(new A (9,9) );

А все смарт посему не катят хош буст хош не буст
Re[6]: delete и delete[ ]
От: Programador  
Дата: 07.03.07 17:00
Оценка:
только проверить нужно наверно там 7 а не F
Re[7]: delete и delete[ ]
От: Programador  
Дата: 07.03.07 17:33
Оценка:
пожалуй inline operator T*() нужно убрать и пользовать так

A *b=x?&new A():new Abc(..)
MAKRO(A,b)
// autoVelo<A> const MOZGI_NE_POMNIT##b(b);
Re[6]: delete и delete[ ]
От: Zigmar Израиль  
Дата: 07.03.07 19:34
Оценка:
Здравствуйте, Programador, Вы писали:
P>
P>     if(0xF&(unsigned)(void*)privatPtr)
P>


Это что за бред такой?! Ты полагаешься на какие-то особенности выделения памяти на каком-то конкретном компиляторе и платформе. Более того, я думаю что это даже на том-же компиляторе не завалится, если чуть чуть поменять настройки или например, тип будет с какой-нибудь виртуальным наследованием или еще какой особенностью. И это не называется "велосипед" — это, скорее можно отнести к разряду опасных багов.

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"
Re[7]: delete и delete[ ]
От: Programador  
Дата: 08.03.07 13:07
Оценка:
Здравствуйте, Zigmar, Вы писали:

А разве я обещал что-то гарантировать я даже в релизе эту вещь не проверял. И вообще не понитаю зачем в 32 нужна грануляция больше 4. Но здесь по дизайну нужно 2 константных, без оператора= один типа режеренс, для симуляции автоматической (автоматической в семантике С++) переменной, второй для симуляции автоматического массива.
Re[2]: delete и delete[ ]
От: Аноним  
Дата: 08.03.07 14:11
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>На самом деле, весьма вероятно, что произойдет разрушения кучи. Не вызов деструкторов по сравнению с этим -- мелкое хулиганство.


Не "мелкое хулиганство", а утечка памяти. При работе в цикле это очень быстро способно вычерпать всю память и поставить машину на колени.
Например, недавно поступила жалоба, что некоторая софтина сжирает гиг памяти. Выяснилось, что причина — утечки памяти. Небольшие, но регулярные.
Re[8]: delete и delete[ ]
От: Аноним  
Дата: 08.03.07 14:21
Оценка:
Здравствуйте, MikelSV, Вы писали:

MSV>Может не совсем правильное, но быстрое решение задачи


Мой дорогой друг, желаю Вам скорейшего попадания в большую команду, где любое скорейшее но не совсем правильное решение будет вылезать на глаза. Тогда оптимизма у Вас поубавится. А сейчас Вы просто живете за счет Вашего последователя, бездумно сваливая на его голову ворох Ваших нерешенных проблем.

И уж он Вас вспомнит не раз и не два, делом и словом. Коротким, но не совсем добрым
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.