Вопрос по динамической памяти...
Речь не идет об освобождении памяти выделенной с помощью new через ф-ию free.
Речь идет о создании динамического массива на основе malloc, realloc, free и запихивании в него указателей созданных через new.
Речь не идет об освобождении памяти выделенной с помощью new через ф-ию free.
Речь идет о создании динамического массива на основе malloc, realloc, free и запихивании в него указателей созданных через new.
честно говоря никогда не пробовала, возможно стоит ))
если не секрет, почему возникла такая необходимость?
Ну собственно, если такой подход корректен, то он довольно прост и быстр... Требует минимум кода...
Хм... А разве new использовать сложнее, чем malloc?
С помощью malloc и realloc мы можем создать непрерывный индексный массив, в котрый кидать указатели на объекты созданные через new.
При добавлении каждого нового элемента, мы просто применяем функцию realloc и добавляем место для хранения очередного указателя объекта, а потом копируем этот указатель в выделенную память.
Смутило то, что некоторые знакомы говорят, что якобы new, delete и malloc, realloc, free не могут соседствовать в программе.
В справочнике Шилдта так же не рекомендуется совместное использование этих функций (но не запрещается)...
В принципе, по логике, эти функции нельзя смешивать. Т.е. нельзя освобождать память выделенную через new с помощью free, как и память выделенную через malloc с помощью delete.
Собственно с чем связаны подобные предостережения? Может проблема в каких то внутренних особенностях работы памяти? Или это как то связано с компиляторами?
Сейчас пишу пример на 6м билдере... Пока все работает без проблем. Могут быть какие нибудь подводные камни?
Да я, честно говоря, тоже не совсем понимаю. В какой-то книге прочитала, что так делать нельзя, а почему - там не было сказано :(
Просто из любопытства интересуюсь: что же вас вынуждает смешивать эти функции? Ну, используйте тогда везде malloc и free вместо new и delete.
Собственно с чем связаны подобные предостережения? Может проблема в каких то внутренних особенностях работы памяти? Или это как то связано с компиляторами?
Сейчас пишу пример на 6м билдере... Пока все работает без проблем. Могут быть какие нибудь подводные камни?
Не делай так и все.Несовместимость new/delete u malloc/free имеет подводные камни.Подробно читай об этих камнях у Скотт Майерс Эффективное использование С++(50 рекомендаций ...).Скотт Майерс -
это тот,кому ты можешь поверить на слово.:) См.Правило 3.Предпочитайте
new и delete использованию malloc и free.(стр.31-33).
С помощью malloc и realloc мы можем создать непрерывный индексный массив, в котрый кидать указатели на объекты созданные через new.
При добавлении каждого нового элемента, мы просто применяем функцию realloc и добавляем место для хранения очередного указателя объекта, а потом копируем этот указатель в выделенную память.
Смутило то, что некоторые знакомы говорят, что якобы new, delete и malloc, realloc, free не могут соседствовать в программе.
В справочнике Шилдта так же не рекомендуется совместное использование этих функций (но не запрещается)...
В принципе, по логике, эти функции нельзя смешивать. Т.е. нельзя освобождать память выделенную через new с помощью free, как и память выделенную через malloc с помощью delete.
Собственно с чем связаны подобные предостережения? Может проблема в каких то внутренних особенностях работы памяти? Или это как то связано с компиляторами?
Сейчас пишу пример на 6м билдере... Пока все работает без проблем. Могут быть какие нибудь подводные камни?
Вместо того, что бы использовать С в С++, лучше научиться использовать С++.
В данном случае лучше использовать контейнеры, например, std::vector, чем городить огород с realloc и т.п.
malloc и free тут в принципе не особо сдались... Единственная вкусность, что с помощью этих функций можно зарезервировать произвольный объем памяти и дальше с помощью realloc произвольно изменять этот объем. По этому объему легко перемещаться. Практически не требуется никаких дополнительных процедур. Работа с элементами аналогична работе с массивом.
new и delete работают с памятью выделяемой под единичные экземпляры объектов.
GreenВ данном случае лучше использовать контейнеры, например, std::vector, чем городить огород с realloc и т.п.
В том то и дело, что при работе с realloc можно сделать все довольно просто, без лишних библиотек... Или все же нельзя? Пойду почитаю материал от m_Valery...
Кстати еще размышлений по поводу совместного использования malloc/realloc/free с new/delete в одной программе... Одним из основополагающих принципов С/С++ является инкапсуляция данных. Не важно как все сделано внутри, важно какие данные выдаются наружу. Если предположить, что в одной программе используются модули разных разработчиков, вполне может возникнуть ситуация, что один использовал malloc/realloc/free, а другой new/delete... По идее, согласно принципу инкапсуляции, оба модуля должны корректно работать друг с другом?
В том то и дело, что при работе с realloc можно сделать все довольно просто, без лишних библиотек...
Что значит "лишние библиотеки" ?
STL - это часть стандартной библиотеки С++.
А вот realloc - это пережиток старого.
Кстати еще размышлений по поводу совместного использования malloc/realloc/free с new/delete в одной программе... Одним из основополагающих принципов С/С++ является инкапсуляция данных. Не важно как все сделано внутри, важно какие данные выдаются наружу. Если предположить, что в одной программе используются модули разных разработчиков, вполне может возникнуть ситуация, что один использовал malloc/realloc/free, а другой new/delete... По идее, согласно принципу инкапсуляции, оба модуля должны корректно работать друг с другом?
Инкапсуляция - это не принцип С++ и уж тем более не принцип С. Это принцип ООП.
Только вот realloc противоречит этим принципам, т.к. нарушает типовую безопасность.
Зачем к современной машине приделывать деревянные колеса от телеги?
В принципе, как я и думал, проблем совместного использования malloc/realloc/free и new/delete не возникает, если не косячить с выделением и освобождением памяти мешая разные группы функций.
Т.е. в программе при выделении и освобождении памяти должны применяться только парные функции malloc - free и new - delete. Но никак не смесь malloc - delete или new - realloc/free.
А так, проблем возникнуть не должно.
Только вот realloc противоречит этим принципам, т.к. нарушает типовую безопасность.
Каким образом нарушает?!
При таком подходе (забивание гвоздей микроскопом, именно так ты пытаешься использовать С++) проблемы у тебя возникнут. Да они у тебя уже возникли, только ты их пока не замечаешь и не признаешь.
Совет: отвлекись от realloc и пр. C-style, попробуй использовать мощь ООП.
И проверить корректность восстановления ты не можешь.
Я уже неоднократно об этом писал.
Воспользуйся поиском по ключам "типовая безопасность", "безопасность типов".
http://forum.codenet.ru/showthread.php?p=126925&highlight=%F2%E8%EF%EE%E2%E0%FF+%E1%E5%E7%EE%EF%E0%F1%ED%EE%F1%F2%FC#post126925
http://forum.codenet.ru/showthread.php?p=35420&highlight=%F2%E8%EF%EE%E2%E0%FF+%E1%E5%E7%EE%EF%E0%F1%ED%EE%F1%F2%FC#post35420
Можешь поискать в интернете, много поучительного найдешь.
Почему бы не посмотреть ссылки приведеные выше?
А разве нельзя функцией new выделять массивы объектов?
А разве нельзя функцией new выделять массивы объектов?
x = new int[323];
Можно и для массивов память выделять.
Но только вот new - это оператор, а не функция. Со всеми вытекающими.
Кстати функция realloc меняет не только размер, но и значение указателя значит ли это, что выделяется новый массив, копируется старый, старый освобождается?
Кстати функция realloc меняет не только размер, но и значение указателя значит ли это, что выделяется новый массив, копируется старый, старый освобождается?
Конечно.
x = new int[323];
Можно и для массивов память выделять.
Но только вот new - это оператор, а не функция. Со всеми вытекающими.
Опять же в указанном примере, массив имеет фиксированную длинну.
Модифицировать уже объявленный массив не представляется возможным. К примеру, если новые элементы в массив должны добавляться в цикле for или while.
HumanAPI
А какая тогда разница между new и malloc и realloc?
Разница в том, что область памяти выделенная через new не может быть перераспределена. Она может только быть освобождена через delete. Функция realloc может изменять размер памяти выделенной с помощью malloc. Ну а типы контролируются через приведение типов при вызове malloc и realloc. Конечно для хранения таких типов как классы, больше подходят new и delete. Т.к. они в отличии от malloc и free выдывают конструкторы и деструкторы классов. Но для таких типов данных как указатели или примитивы, ф-ии malloc / realloc / free вполне сгодяться.
Разница в том, что область памяти выделенная через new не может быть перераспределена. Она может только быть освобождена через delete. Функция realloc может изменять размер памяти выделенной с помощью malloc.
Ага, причем изменение размера с помощью realloc ничем не отличается от delete/new, только здесь free/malloc.
Ну а типы контролируются через приведение типов при вызове malloc и realloc.
Какое привидение типов?! Какой контроль?! О чем ты?!
malloc и realloc работают с самым бесконтрольным и опасным типом void*.
Но для таких типов данных как указатели или примитивы, ф-ии malloc / realloc / free вполне сгодяться.
В С++ не сгодяться, сколько можно повторять?
Что ты носишься с realloc как с писанной торбой. Уже несколько раз сказали: realloc/malloc/free - это ПЛОХОЙ СТИЛЬ ПРОГРАММИРОВАНИЯ НА С++.
Привди хотя бы один пример (в виде кода), когда без realloc не обойтись, или хотябы он предпочтительнее.
Ага, причем изменение размера с помощью realloc ничем не отличается от delete/new, только здесь free/malloc.
Что то не понятен смысл... Что значит "изменение размера с помощью realloc ничем не отличается от delete/new"?! Каким образом new/delete могут перераспределять выделенную память?
Что ты носишься с realloc как с писанной торбой. Уже несколько раз сказали: realloc/malloc/free - это ПЛОХОЙ СТИЛЬ ПРОГРАММИРОВАНИЯ НА С++.
Я не люблю белых пятен в знаниях. Чтобы избегать ошибок, нужно знать к каким последствиям эти ошибки ведут.
P.S. Вот заметил, что часто на разных форумах, когда человек спрашивает совета как "научится плохому", ему обычно отвечают что этому учиться не надо :)
Что то не понятен смысл... Что значит "изменение размера с помощью realloc ничем не отличается от delete/new"?! Каким образом new/delete могут перераспределять выделенную память?
http://www.cplusplus.com/reference/clibrary/cstdlib/realloc.html
[/QUOTE]
у меня есть сильные подозрения, что таким же образом, что и функция realloc, ответ есть здесь же в топике: http://forum.codenet.ru/showpost.php?p=196743&postcount=22
просто напиши свою функцию, которая при помощи оператора new создает новый массив с нужным размером, переписывает элементы старого массива в него же ну и после этого сохраняет указатель на новый массив в указателе на старый массив, предварительно освободив память, которую он занимал. что-то вроде этого.
1. Вектор писали знающие люди.
2. Вектор реализован на каждой платформе по-своему, его реализовывали те же люди, что писали платформу. Поэтому логично предположить, что он реализован так, чтобы наиболее полно использовать возможности именно данного компилятора, чтобы он компилировался наиболее оптимально для данного компилятора.
3. Я сомневаюсь, что вы, уважаемый начинающий программер, напишете что-то более безопасное и переносимое, нежели std::vector.
4. realloc может выделить память в новом месте, и тогда он просто скопирует содержимое в новое место. Но он не будет вызывать оператор копирования для данного типа (см. сообщение Green'а о безопасности типов: realloc использует void*). А ведь может оказаться, что копирование для данного типа - нетривиально (т. е. просто memcpy не годится). Более того, может оказаться, что наш тип имеет семантику NonCopyable (некопируемый), а realloc тупо побайтно скопирует содержимое, а копирование ведь вообще не разрешено для данного типа, коль скоро он NonCopyable.
5. Для использования new/delete можно выделять немного больше места, чем нужно в данный момент. Т. е. нам нужно сейчас, в данный момент, хранить 28 объектов, а мы выделяем место сразу для 32, имея резерв в 4 лишних объекта.
Для подобных операций C++ предусматривает:
1) Вызов оператора new так, чтобы он не вызывал конструктор. Для этого используйте вместо записи
2) В момент добавления элемента в массив, в том случае, если имеется уже выделенное и неинициализированное место, используйте опять же оператор new, но уже в "нормальном" виде, но нужно использовать "размещающий" оператор new (такая форма оператора, наоборот, не выделяет место, а лишь вызывает конструктор). Вызов выглядит примерно так:
Для уточнения см. http://forum.codenet.ru/showthread.php?t=38979
И проверить корректность восстановления ты не можешь.
Слушай, а что насчет приведения типов?? Это ведь тоже получается информация извне программы. То-есть например у меня есть что-то похожее:
int Encrypt(int Length, unsigned char * In, unsigned char * Out);
// немного упрощенно, но пусть будет
Скажем функция эта находится во внешней либе.
А у меня есть переменная:
wchar_t * DecryptedData;
wchar_t * EncryptedData;
Как мне в таком случае обойти конструкцию:
Encrypt((unsigned char *)DecryptedData, (unsigned char *)EncryptedData);
или как обойти конструкцию вроде
unsigned char * VeryLargeBuffer;
unsigned char * pBuffer = VeryLargeBuffer;
int Offset = 0;
for (int counter = 0; counter < MaxBufferLength; counter++)
{
if (<неважно что>)
{
Offset ++;
pBuffer = (unsigned char *)((int)VeryLargeBuffer + Offset);
}
}
Я например путей для улучшения такого кода не вижу ((
int Encrypt(int Length, unsigned char * In, unsigned char * Out);
// немного упрощенно, но пусть будет
Скажем функция эта находится во внешней либе.
А у меня есть переменная:
wchar_t * DecryptedData;
wchar_t * EncryptedData;
Как мне в таком случае обойти конструкцию:
Encrypt((unsigned char *)DecryptedData, (unsigned char *)EncryptedData);
Функция по сути C-шная, и раз уж она находится во внешней библиотеке, ничего не поделаешь.
Но если функцию пишешь сам, используй шаблоны:
{
// Код функции
};
Это типобезопасная конструкция, преобразование типов не потребуется.
или как обойти конструкцию вроде
unsigned char * VeryLargeBuffer;
unsigned char * pBuffer = VeryLargeBuffer;
int Offset = 0;
for (int counter = 0; counter < MaxBufferLength; counter++)
{
if (<неважно что>)
{
Offset ++;
pBuffer = (unsigned char *)((int)VeryLargeBuffer + Offset);
}
}
Я например путей для улучшения такого кода не вижу ((
unsigned char * pBuffer = VeryLargeBuffer;
// int Offset = 0; [color=red]В этой переменной нет необходимости[/color]
for (int counter = 0; counter < MaxBufferLength; [color=red]++counter[/color])
{
if (<неважно что>)
{
++pBuffer; //[color=red]Для указателей работают операции сложения, вычитания, инкремент и декремент[/color]
}
}
Примечание: counter++ я заменил на ++counter, поскольку нужно предпочитать прединкремент постинкременту, т. к. прединкремент работает чуть быстрее.
А Offset можно получить (если он нужен) вычитанием из pBuffer VeryLargeBuffer.
так работать не будет, из-за несоответствия типов:
unsigned char * pBuffer = VeryLargeBuffer;
pBuffer += 0x20;
так работать не будет, из-за несоответствия типов:
unsigned char * pBuffer = VeryLargeBuffer;
pBuffer += 0x20;
Будет.
Напоминаю правила сложения/вычитания указателей.
К указателю можно прибавить или вычесть любое целое число, это будет расцениваться как "сдвиг" указателя на соответствующее число объектов, на который указывает указатель.
Т. е.
pointer += 50;
После такой операции pointer будет указывать на 50-й элемент массива, каким бы ни был тип SomeType.
К тому же приведенный тобой код
не является безопасным, т. к. при преобразовании VeryLargeBuffer никто не гарантирует, что значение указателя поместится в int, или наоборот, при преобразовании значения ((int)VeryLargeBuffer + Offset) в unsigned char* не гарантируется, что int поместится в указатель. Если в твоем конкретном компиляторе на твоей конкретной ОС размер int'а 32 бит и размер указателя 32 бит, это еще не значит, что на других компиляторах то же самое. Например, в 16-битной MS-DOS компиляторы обычно расценивают int как 16-битное значение, а вот дальний указатель 32-битный.
В крайнем случае надо писать
такая запись безопасна.
щас буду избавляться от варнингов в прожекте ))