А>class MyInfo
А>{
А> int ptr,p2,p4;
А> long long p3;
А>};
А>
А>sizeof возвращает 24 А>это из за выравнивания по-умолчанию?
А>кстати память выделенная new[] можно освобождать delete (без[]) А>т.е. работает, но не вызывается деструктор эл. массива?
Здравствуйте, Аноним, Вы писали:
А>проверял один класс А>и наткнулся на такую вещь
А>
А>class MyInfo
А>{
А> int ptr,p2,p4;
А> long long p3;
А>};
А>
А>sizeof возвращает 24 А>это из за выравнивания по-умолчанию?
А>кстати память выделенная new[] можно освобождать delete (без[]) А>т.е. работает, но не вызывается деструктор эл. массива?
Выравнивание по умолчанию зависит от компилятора.
Возврат памяти массива без [] — ИМХО ляп разработчиков компилятора.
Не следует пользоваться во избежание проблем.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Аноним, Вы писали:
А>проверял один класс А>и наткнулся на такую вещь
А>
А>class MyInfo
А>{
А> int ptr,p2,p4;
А> long long p3;
А>};
А>
А>sizeof возвращает 24 А>это из за выравнивания по-умолчанию?
А>кстати память выделенная new[] можно освобождать delete (без[]) А>т.е. работает, но не вызывается деструктор эл. массива?
1. выравнивание зависит от настроек компилятора
2. new [] и delete без [] это UB. Так делать крайне не рекомендую.
Re: бояны-бояны... (что вернёт sizeof + delete vs delete[])
Здравствуйте, Аноним, Вы писали:
А>sizeof возвращает 24 А>это из за выравнивания по-умолчанию?
На такой вопрос я уже как-то твечал
А>кстати память выделенная new[] можно освобождать delete (без[]) А>т.е. работает, но не вызывается деструктор эл. массива?
На такой тоже, но не могу найти сразу.
Если коротко, то очень зависит от компилятора и типа, который ты по new создавал.
Общий смысл такой, что компиляторы, когда ты аллокируешь массив данных с нетривиальными деструкторами/конструкторами или просто не POD, перед началом вектора оставляют немного места, чтобы записать туда длину этого массива.
Ну, то есть, они так смотрят, ты хочешь создать вектор из shared_ptr<T>, например.
new shared_ptr<int>[5];
и понимают, что когда ты будешь это дело разрушать, то кроме того, что надо будет освободить память из-под самого вектора, надо будет ещё и вызвать деструкторы у пяти его элементов.
поэтому компилятор вызывает функцию ::operator new[]( sizeof( size_t) + sizeof(shared_ptr<int>) * 5), потом по адресу, который вернул ::operator new[] записывает 5, а по адресу + 4 создаёт пять идущих один за другим объектов, и возвращает адрес первого из них.
При вызове delete[] компилятор видит, что тип элемента вектора такой, что "в заначке" должен быть счётчик, поэтому вычитают из переданного адреса 4, смотрят на счётчик, и разрушают пять объектов. А потом вызывают от уменшенного на 4 адреса ::operator delete[]()
То есть отличие состоит не только в том, что не зовутся деструкторы, но и в том, что в ::operator delete[] прийдут РАЗНЫЕ АДРЕСА! А это вот уже может фатально повредить кучу...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали: А>кстати память выделенная new[] можно освобождать delete (без[]) А>т.е. работает, но не вызывается деструктор эл. массива?
Нет.
In the first alternative (delete object), the value of the operand of delete may be a null pointer
value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8)
representing a base class of such an object (Clause 10). If not, the behavior is undefined.
зачем минусовать?
я то просил потому как считал если везде пишут что нельзя так делать (new-delete разные)
то и выйдет ошибка при работе программы
а тут все срабатывает, вроде хорошо, но ведь поменяй что то в классе например,
который используется как эл. массива, то в какой то момент да рухнет все
Re[2]: бояны-бояны... (что вернёт sizeof + delete vs delete[
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Аноним, Вы писали:
А>>sizeof возвращает 24 А>>это из за выравнивания по-умолчанию?
E>На такой вопрос я уже как-то твечал
А>>кстати память выделенная new[] можно освобождать delete (без[]) А>>т.е. работает, но не вызывается деструктор эл. массива? E>На такой тоже, но не могу найти сразу.
E>Если коротко, то очень зависит от компилятора и типа, который ты по new создавал. E>Общий смысл такой, что компиляторы, когда ты аллокируешь массив данных с нетривиальными деструкторами/конструкторами или просто не POD, перед началом вектора оставляют немного места, чтобы записать туда длину этого массива.
E>Ну, то есть, они так смотрят, ты хочешь создать вектор из shared_ptr<T>, например. E>
new shared_ptr<int>[5];
и понимают, что когда ты будешь это дело разрушать, то кроме того, что надо будет освободить память из-под самого вектора, надо будет ещё и вызвать деструкторы у пяти его элементов.
E>поэтому компилятор вызывает функцию ::operator new[]( sizeof( size_t) + sizeof(shared_ptr<int>) * 5), потом по адресу, который вернул ::operator new[] записывает 5, а по адресу + 4 создаёт пять идущих один за другим объектов, и возвращает адрес первого из них.
E>При вызове delete[] компилятор видит, что тип элемента вектора такой, что "в заначке" должен быть счётчик, поэтому вычитают из переданного адреса 4, смотрят на счётчик, и разрушают пять объектов. А потом вызывают от уменшенного на 4 адреса ::operator delete[]()
E>То есть отличие состоит не только в том, что не зовутся деструкторы, но и в том, что в ::operator delete[] прийдут РАЗНЫЕ АДРЕСА! А это вот уже может фатально повредить кучу...
последние 2 абзаца не очень понял
что значит А потом вызывают от уменшенного на 4 адреса ::operator delete[]()?
ведь уже работает delete[]
или это для new[][]... ?
но и в том, что в ::operator delete[] прийдут РАЗНЫЕ АДРЕСА!
всмысле будет вызываться delete() для каждого из 5 адресов например?
Item::AllocateVector( 5 )
Item::operator new[]( 9 ) = 0xFAA18
Item::AllocateVector: ptr = 0xFAA1C, count = 5
Item::SetI( 0 ): this = 0xFAA1C
Item::SetI( 1 ): this = 0xFAA1D
Item::SetI( 2 ): this = 0xFAA1E
Item::SetI( 3 ): this = 0xFAA1F
Item::SetI( 4 ): this = 0xFAA20
Item::~Item : this = 0xFAA20, I = 4
Item::~Item : this = 0xFAA1F, I = 3
Item::~Item : this = 0xFAA1E, I = 2
Item::~Item : this = 0xFAA1D, I = 1
Item::~Item : this = 0xFAA1C, I = 0
Item::operator delete[]( 0xFAA18 )
Что это значит? Что есть С++ конструкция new Item[5] и есть функция operator new[]( size_t size ). И, аналогично, есть С++ конструкция delete[] pItems и есть функция operator delete[]( void* )
Конструкция new Item[5] вычисляет размре Item'а, умножает его на 5, и прибавляет к этим 5 байтам ещё 4 байта на хранение счётчика! итого выходит 9 байт, их С++ и передаёт в operator new[], тот выделяет память по адресу 0xFAA18 и возвращает ее С++.
После чего С++ пишет по этому адресу счётчик элементов массива, а сами элементы размещает с адреса 0xFAA1C, то есть с 0xFAA18 + 4
После этого С++ конструкция new Item[5] возвращает адрес вевсе и не начала выделенного буфера в памяти (0xFAA18), а адрес первого элемента ветора (0xFAA1C).
Теперь мы работаем с этим вектором (вызываем у всех элемнтов SetI, который, кроме всего прочего, распечатывает нам this, каждого из них), потом зовём C++ сонструкцию delete[], передавая в неё адрес 0xFAA1C, а не 0xFAA18.
Она считывает 5 из заныканного счётчка, вызывает деструкторы, потом вычитает 4 и вызывает функцию operator delete[] от 0xFAA1C.
А если мы позовём просто delete, то она не будет искать счётчик, позовёт деструктор только у одного объекта и передаст в функцию operator delete() НЕ ТОТ АДРЕС блока. То есть 0xFAA1C, вместо 0xFAA18, который вырнул аллокатор!
Для большинства аллокаторов это обозначате разрушение внутренней слогической структуры и совершенно непредсказуемые последствия!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Erop, спасибо за подробное разъяснение
я кстати заметил что если вместо настоящго класса использовать простую структуру (или new int[size] например)
то ptr=new MyStruct[size]
ptr[-1] не будет лежать кол-во элементов
наверное о гето в другом месте лежит
(оптимизацию я выключил компиляции)
Здравствуйте, locker, Вы писали:
L>Erop, спасибо за подробное разъяснение
Пожалуйста, обращайся.
Для "спасибо" тут есть кнопки.
L>я кстати заметил что если вместо настоящго класса использовать простую структуру (или new int[size] например)
В С++ такие данные называются аббревиатурой POD (Plain Old Data).
L>то ptr=new MyStruct[size] L>ptr[-1] не будет лежать кол-во элементов L>наверное о где-то в другом месте лежит L>(оптимизацию я выключил компиляции)
Нет, нигде не лежит. Тут вот какое дело, такие тонкие подробности реализации различаются у разных компиляторов. Чтобы разговор был предметным, то стоит оговоирить о каком компиляторе мы говорим.
Если мы о VC, то он смотрит, есть ли у типа элемента динамически аллокируемого вектора нетривиальный деструктор. Если есть, то при вызове delete[] надо будет позвать дестуркторы всех созданных в векторе объектов, а для этого надо знать, сколько их было. Вот он и делает "заначку" в памяти, под счётчик.
А если мы аллокируем вектор POD'ов, или других каких-то объектов, с тривиальным деструктором, то деструкторы звать не надо, соответственно и занать, сколько объектов должно быть разрушено не надо, соответственно и счётчик не нужен. В этом случае VC++ просто передаёт в operator new[]() чсло sizeof(Item) * countOfItems, и никаких начек не делает, и указатель не сдвигает.
Ну и delete[] в этом случае, тоже ничего не сдвигает, деструкторы не зовёт, а просто вызывает operator delete[] от переданного в конструкцию delete[] указателя и всё.
В частности, это значит, что на текущей реализации компилятора VC++ вектор POD-типов можно разрушать конструкцией delete БЕЗ квадтартных скобок. В смысле на текущей реализации VC++ это не будет приводить к каким-то наблюдаемым негативным эффектам. Но нет никаких гарантий, что такое поведение сохранится в будущем, и, тем более, нет гарантий, что другие компиляторы ведут себя так же. Так что на такие тонкие хаки лучше бы не закладываться...
Кстати, не поделишься, зачем тебе понадобилось заменить delete[] на delete без []?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Нет, нигде не лежит. Тут вот какое дело, такие тонкие подробности реализации различаются у разных компиляторов. Чтобы разговор был предметным, то стоит оговоирить о каком компиляторе мы говорим.
.....
да, речь идет о VS 2005, но я встречал new POD_Type[size]-delete (без []) в исходном коде, которая была откомпилированна в vs 2010,g++ (MiniGW),Intel Parallel Studio 2011
и они все успешно работают ))
я догадался что с ПОДами это не надо, но я думал что с смещением -1 хранится тогда размер выделенного блока (кстати тогда где он храниться,или есть какая та таблица ptr-size?)
(SuperREP (SREP) huge-dictionary LZ77 preprocessor, хорошо сжимает файлы с текстурами/данными, в репаках игр часто используется, сначала сжимают срепом, потом еще можно хорошо пожать lzma)
E>Кстати, не поделишься, зачем тебе понадобилось заменить delete[] на delete без []?
я как раз этого не хотел делать, но когда я встретил в исходном коде шаблон массива, то я заметил что там несоответствие new/delete
(вот так, нахожу всякие мелочи когда сам нечего толкового не могу написать)) как человек с комитета стандартизации))) )
написал автору, он написал чуть больше чем я в первом посте написал (под анонимом еще)
а вообще я исходник этой проги уже давно смотрю периодически, потмоу как смотреть исходник 7z/LZMA это ужас ))
проект FreeArc, архиватор с множеством алгоритмов сжатия и ручной настройкой методов сжатия (что очень круто), также есть возможжность использовать цепочку алгоритмов, например 4x4 алгоритм + lzma намультипроцессорных/многоядерных ПК дает хороший прирость скорости сжатия, првада память немлохо съест и немного ухудшится степень сжатия
вот тут
последние новости и с автором можно поговорить тут
имя автора кстати в благодарнастях WinRAR можно встретить (Булат Зиганшин)
Здравствуйте, Erop, Вы писали:
E>и передаст в функцию operator delete() НЕ ТОТ АДРЕС блока. То есть 0xFAA1C, вместо 0xFAA18, который вырнул аллокатор!
Ну да и что? Вместо имени массива (как и положено) подставлен указатель на первый его элемент, т.е. 0xFAA1C. Можно (вообще-то, не надо) сделать еще и вот так:
Item* items = new Items[5];
//....
Item* p = &items[0];
delete p; // вызываем ::operator delete(0xFAA1C), и возвращаем в "кучу" кусок памяти, который занимал первый элемент массива items...
//...delete [] items; // пытаемся вернуть в "кучу" все остальное, что при этом произойдет - вряд ли ответят даже разработчики компилятора...
ИМХО, проблема не в том, что
Для большинства аллокаторов это обозначает разрушение внутренней логической структуры
, а в том, что мы будем дважды возвращать в "кучу" один и тот же кусок памяти: в первый раз сам по себе, во второй раз — как часть массива. Интересный (чисто теоретически) вопрос, лечится ли это реализацией собственных версий operator new, operator new[], operator delete и operator delete[] — для конкретного класса или "в мировом масштабе"? Стандарт-то суров:
If not, the behavior is undefined
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, locker, Вы писали:
L>я догадался что с ПОДами это не надо, но я думал что с смещением -1 хранится тогда размер выделенного блока (кстати тогда где он храниться,или есть какая та таблица ptr-size?)
Это отдано на ответственность аллокатора, и клиентам аллокатора не видно.
Например, аллокатор может гранулировать размер запрашиваемого болока и выделать память из разных диапазонов, соответствующих разным гранулам. Соотвественно, он по адресу сразу узнет размер...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, slava_phirsov, Вы писали:
E>>и передаст в функцию operator delete() НЕ ТОТ АДРЕС блока. То есть 0xFAA1C, вместо 0xFAA18, который вырнул аллокатор!
_>Ну да и что? Вместо имени массива (как и положено) подставлен указатель на первый его элемент, т.е. 0xFAA1C. Можно (вообще-то, не надо) сделать еще и вот так:
Это не так. И указатель на массив, и указатель на первый элемент в С++/С всегда совпадают, и в этом примере и то и то будет 0xFAA1C...
Адрес 0xFAA18 -- это уже кишки реализации, которые
1) Нестандартные
2) Не видны непосредственно
_>...а в том, что мы будем дважды возвращать в "кучу" один и тот же кусок памяти: в первый раз сам по себе, во второй раз — как часть массива. Интересный (чисто теоретически)
Это другая проблема. ТС вроде как не про это писал...
Стандарт-то суров:
If not, the behavior is undefined
Дык ясно, что так делать не надо, но всегда интересно знать. что будет, если сделаешь "как не надо"...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
лечится ли это реализацией собственных версий operator new, operator new[], operator delete и operator delete[]
Скорее нет, чем да. Насколько я понимаю, подумавши как следует, таким образом можно только изменить способ выделения/утилизации памяти, не более того.
P.S. В качестве источника сошлюсь на Майерса, 2-я книга, "Правило 8", где в доступной (во всяком случае, для меня), хотя и упрощенной форме, объясняется разница между оператором new и функцией operator new
P.P.S. Если я не прав — поправьте.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Здравствуйте, slava_phirsov, Вы писали:
_>P.P.S. Если я не прав — поправьте.
Если честно, то не ясно, что именно ты хочешь личить? То, что аллокаторо может утилизировать только весь блок сразу? Ну так можешь написать свой аллокатор, который умеет и так и сяк, выделять на нём память, а объекты создавать по new размещения.
Завернуть всё это в набор шаблонных функций или методов, чтобы не зависеть от особенностей реализации new и delete и получить фабрику векторов обхектов, которые можно освобождать по частям...
Вопрос в том, на кой это могло бы быть надо...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gegMOPO4, Вы писали:
E>>Дык ясно, что так делать не надо, но всегда интересно знать. что будет, если сделаешь "как не надо"... MOP>«Ага…» — сказали суровые сибирские мужики и сунули под японскую пилу железный лом.
1) Да, я родился и вырос в Сибири.
2) Понимать, как ломает программу то или иное UB, полезно, напирмер, для отладки всяких "гейзен-багов"...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском