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
Оценка:
Короче, окончательно затуманили мой мозг! Спасибо...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.