Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вопрос по динамической памяти...

590
07 июня 2007 года
Gigahard
223 / / 03.04.2006
Можно ли в одной программе совместно использовать C++ функции (new, delete) и Си функции (malloc, realloc, free)?

Речь не идет об освобождении памяти выделенной с помощью new через ф-ию free.
Речь идет о создании динамического массива на основе malloc, realloc, free и запихивании в него указателей созданных через new.
242
07 июня 2007 года
Оlga
2.2K / / 04.02.2006
Цитата: Gigahard
Можно ли в одной программе совместно использовать C++ функции (new, delete) и Си функции (malloc, realloc, free)?

Речь не идет об освобождении памяти выделенной с помощью new через ф-ию free.
Речь идет о создании динамического массива на основе malloc, realloc, free и запихивании в него указателей созданных через new.


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

590
07 июня 2007 года
Gigahard
223 / / 03.04.2006
Цитата:
если не секрет, почему возникла такая необходимость?


Ну собственно, если такой подход корректен, то он довольно прост и быстр... Требует минимум кода...

15K
07 июня 2007 года
Sara
79 / / 04.01.2007
Цитата: Gigahard
Ну собственно, если такой подход корректен, то он довольно прост и быстр... Требует минимум кода...


Хм... А разве new использовать сложнее, чем malloc?

590
07 июня 2007 года
Gigahard
223 / / 03.04.2006
У new и delete нет аналога realloc и не можем менять размер уже выделенной памяти. Для этого приходиться пользоваться другим подходом и создавать конструкции типа связанных списков.

С помощью malloc и realloc мы можем создать непрерывный индексный массив, в котрый кидать указатели на объекты созданные через new.
При добавлении каждого нового элемента, мы просто применяем функцию realloc и добавляем место для хранения очередного указателя объекта, а потом копируем этот указатель в выделенную память.

Смутило то, что некоторые знакомы говорят, что якобы new, delete и malloc, realloc, free не могут соседствовать в программе.
В справочнике Шилдта так же не рекомендуется совместное использование этих функций (но не запрещается)...
В принципе, по логике, эти функции нельзя смешивать. Т.е. нельзя освобождать память выделенную через new с помощью free, как и память выделенную через malloc с помощью delete.

Собственно с чем связаны подобные предостережения? Может проблема в каких то внутренних особенностях работы памяти? Или это как то связано с компиляторами?

Сейчас пишу пример на 6м билдере... Пока все работает без проблем. Могут быть какие нибудь подводные камни?
15K
07 июня 2007 года
Sara
79 / / 04.01.2007
[QUOTE="Gigahard"]Собственно с чем связаны подобные предостережения? Может проблема в каких то внутренних особенностях работы памяти? Или это как то связано с компиляторами?[/QUOTE]
Да я, честно говоря, тоже не совсем понимаю. В какой-то книге прочитала, что так делать нельзя, а почему - там не было сказано :(
Просто из любопытства интересуюсь: что же вас вынуждает смешивать эти функции? Ну, используйте тогда везде malloc и free вместо new и delete.
23K
07 июня 2007 года
HumanAPI
18 / / 07.03.2007
А почему не написать собственную функцию для изменения массивов при помощи new delete и ни каких подводных камней.
320
07 июня 2007 года
m_Valery
1.0K / / 08.01.2007
Цитата: Gigahard
...Т.е. нельзя освобождать память выделенную через new с помощью free, как и память выделенную через malloc с помощью delete.

Собственно с чем связаны подобные предостережения? Может проблема в каких то внутренних особенностях работы памяти? Или это как то связано с компиляторами?

Сейчас пишу пример на 6м билдере... Пока все работает без проблем. Могут быть какие нибудь подводные камни?


Не делай так и все.Несовместимость new/delete u malloc/free имеет подводные камни.Подробно читай об этих камнях у Скотт Майерс Эффективное использование С++(50 рекомендаций ...).Скотт Майерс -
это тот,кому ты можешь поверить на слово.:) См.Правило 3.Предпочитайте
new и delete использованию malloc и free.(
стр.31-33).

3
07 июня 2007 года
Green
4.8K / / 20.01.2000
Цитата: Gigahard
У new и delete нет аналога realloc и не можем менять размер уже выделенной памяти. Для этого приходиться пользоваться другим подходом и создавать конструкции типа связанных списков.

С помощью malloc и realloc мы можем создать непрерывный индексный массив, в котрый кидать указатели на объекты созданные через new.
При добавлении каждого нового элемента, мы просто применяем функцию realloc и добавляем место для хранения очередного указателя объекта, а потом копируем этот указатель в выделенную память.

Смутило то, что некоторые знакомы говорят, что якобы new, delete и malloc, realloc, free не могут соседствовать в программе.
В справочнике Шилдта так же не рекомендуется совместное использование этих функций (но не запрещается)...
В принципе, по логике, эти функции нельзя смешивать. Т.е. нельзя освобождать память выделенную через new с помощью free, как и память выделенную через malloc с помощью delete.

Собственно с чем связаны подобные предостережения? Может проблема в каких то внутренних особенностях работы памяти? Или это как то связано с компиляторами?

Сейчас пишу пример на 6м билдере... Пока все работает без проблем. Могут быть какие нибудь подводные камни?


Вместо того, что бы использовать С в С++, лучше научиться использовать С++.
В данном случае лучше использовать контейнеры, например, std::vector, чем городить огород с realloc и т.п.

590
07 июня 2007 года
Gigahard
223 / / 03.04.2006
Sara Просто из любопытства интересуюсь: что же вас вынуждает смешивать эти функции? Ну, используйте тогда везде malloc и free вместо new и delete.
malloc и free тут в принципе не особо сдались... Единственная вкусность, что с помощью этих функций можно зарезервировать произвольный объем памяти и дальше с помощью realloc произвольно изменять этот объем. По этому объему легко перемещаться. Практически не требуется никаких дополнительных процедур. Работа с элементами аналогична работе с массивом.

new и delete работают с памятью выделяемой под единичные экземпляры объектов.

GreenВ данном случае лучше использовать контейнеры, например, std::vector, чем городить огород с realloc и т.п.
В том то и дело, что при работе с realloc можно сделать все довольно просто, без лишних библиотек... Или все же нельзя? Пойду почитаю материал от m_Valery...


Кстати еще размышлений по поводу совместного использования malloc/realloc/free с new/delete в одной программе... Одним из основополагающих принципов С/С++ является инкапсуляция данных. Не важно как все сделано внутри, важно какие данные выдаются наружу. Если предположить, что в одной программе используются модули разных разработчиков, вполне может возникнуть ситуация, что один использовал malloc/realloc/free, а другой new/delete... По идее, согласно принципу инкапсуляции, оба модуля должны корректно работать друг с другом?
1.9K
07 июня 2007 года
smax13
63 / / 03.08.2004
имно, лучше используй локальны йкусок памяти для размещения указателей. для выделения - всего несколько тактов проца, да и освобождать не надо. это, правда, если не собираешься создавать "очень" много указателей (тогда надо будет переопределять размер стека). ну локальным, он , конечно должен быть относительно: объяви в глобальной области.
3
07 июня 2007 года
Green
4.8K / / 20.01.2000
Цитата: Gigahard

В том то и дело, что при работе с realloc можно сделать все довольно просто, без лишних библиотек...


Что значит "лишние библиотеки" ?
STL - это часть стандартной библиотеки С++.
А вот realloc - это пережиток старого.

Цитата: Gigahard

Кстати еще размышлений по поводу совместного использования malloc/realloc/free с new/delete в одной программе... Одним из основополагающих принципов С/С++ является инкапсуляция данных. Не важно как все сделано внутри, важно какие данные выдаются наружу. Если предположить, что в одной программе используются модули разных разработчиков, вполне может возникнуть ситуация, что один использовал malloc/realloc/free, а другой new/delete... По идее, согласно принципу инкапсуляции, оба модуля должны корректно работать друг с другом?


Инкапсуляция - это не принцип С++ и уж тем более не принцип С. Это принцип ООП.
Только вот realloc противоречит этим принципам, т.к. нарушает типовую безопасность.

Зачем к современной машине приделывать деревянные колеса от телеги?

590
08 июня 2007 года
Gigahard
223 / / 03.04.2006
Почитал Майерса...
В принципе, как я и думал, проблем совместного использования malloc/realloc/free и new/delete не возникает, если не косячить с выделением и освобождением памяти мешая разные группы функций.
Т.е. в программе при выделении и освобождении памяти должны применяться только парные функции malloc - free и new - delete. Но никак не смесь malloc - delete или new - realloc/free.

А так, проблем возникнуть не должно.

Только вот realloc противоречит этим принципам, т.к. нарушает типовую безопасность.
Каким образом нарушает?!
3
08 июня 2007 года
Green
4.8K / / 20.01.2000
Он оперирует типом void*, а это зло, которое противоречит всем принципам ООП.

При таком подходе (забивание гвоздей микроскопом, именно так ты пытаешься использовать С++) проблемы у тебя возникнут. Да они у тебя уже возникли, только ты их пока не замечаешь и не признаешь.
Совет: отвлекись от realloc и пр. C-style, попробуй использовать мощь ООП.
255
08 июня 2007 года
Dart Bobr
1.4K / / 09.04.2004
а почему собс-но говоря void* - это зло?? Всегда можно написать проверку корректности данных.
3
08 июня 2007 года
Green
4.8K / / 20.01.2000
Потому, что ты безвозвратно теряешь инф. о типе.
И проверить корректность восстановления ты не можешь.

Я уже неоднократно об этом писал.
Воспользуйся поиском по ключам "типовая безопасность", "безопасность типов".
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

Можешь поискать в интернете, много поучительного найдешь.
590
09 июня 2007 года
Gigahard
223 / / 03.04.2006
А использование приведения типов?!
63
09 июня 2007 года
Zorkus
2.6K / / 04.11.2006
Цитата: Gigahard
А использование приведения типов?!

Почему бы не посмотреть ссылки приведеные выше?

23K
09 июня 2007 года
HumanAPI
18 / / 07.03.2007
Gigahard new и delete работают с памятью выделяемой под единичные экземпляры объектов.

А разве нельзя функцией new выделять массивы объектов?
63
09 июня 2007 года
Zorkus
2.6K / / 04.11.2006
Цитата: HumanAPI
Gigahard new и delete работают с памятью выделяемой под единичные экземпляры объектов.
А разве нельзя функцией new выделять массивы объектов?


 
Код:
int *x;
x = new int[323];

Можно и для массивов память выделять.
Но только вот new - это оператор, а не функция. Со всеми вытекающими.
23K
09 июня 2007 года
HumanAPI
18 / / 07.03.2007
А какая тогда разница между new и malloc и realloc?
Кстати функция realloc меняет не только размер, но и значение указателя значит ли это, что выделяется новый массив, копируется старый, старый освобождается?
3
09 июня 2007 года
Green
4.8K / / 20.01.2000
Цитата: HumanAPI

Кстати функция realloc меняет не только размер, но и значение указателя значит ли это, что выделяется новый массив, копируется старый, старый освобождается?


Конечно.

590
10 июня 2007 года
Gigahard
223 / / 03.04.2006
Цитата: Zorkus
 
Код:
int *x;
x = new int[323];

Можно и для массивов память выделять.
Но только вот new - это оператор, а не функция. Со всеми вытекающими.



Опять же в указанном примере, массив имеет фиксированную длинну.
Модифицировать уже объявленный массив не представляется возможным. К примеру, если новые элементы в массив должны добавляться в цикле for или while.

HumanAPI
А какая тогда разница между new и malloc и realloc?
Разница в том, что область памяти выделенная через new не может быть перераспределена. Она может только быть освобождена через delete. Функция realloc может изменять размер памяти выделенной с помощью malloc. Ну а типы контролируются через приведение типов при вызове malloc и realloc. Конечно для хранения таких типов как классы, больше подходят new и delete. Т.к. они в отличии от malloc и free выдывают конструкторы и деструкторы классов. Но для таких типов данных как указатели или примитивы, ф-ии malloc / realloc / free вполне сгодяться.

3
10 июня 2007 года
Green
4.8K / / 20.01.2000
Цитата: Gigahard

Разница в том, что область памяти выделенная через new не может быть перераспределена. Она может только быть освобождена через delete. Функция realloc может изменять размер памяти выделенной с помощью malloc.


Ага, причем изменение размера с помощью realloc ничем не отличается от delete/new, только здесь free/malloc.

Цитата: Gigahard

Ну а типы контролируются через приведение типов при вызове malloc и realloc.


Какое привидение типов?! Какой контроль?! О чем ты?!
malloc и realloc работают с самым бесконтрольным и опасным типом void*.

Цитата: Gigahard

Но для таких типов данных как указатели или примитивы, ф-ии malloc / realloc / free вполне сгодяться.


В С++ не сгодяться, сколько можно повторять?

Что ты носишься с realloc как с писанной торбой. Уже несколько раз сказали: realloc/malloc/free - это ПЛОХОЙ СТИЛЬ ПРОГРАММИРОВАНИЯ НА С++.

Привди хотя бы один пример (в виде кода), когда без realloc не обойтись, или хотябы он предпочтительнее.

590
10 июня 2007 года
Gigahard
223 / / 03.04.2006
Green
Ага, причем изменение размера с помощью realloc ничем не отличается от delete/new, только здесь free/malloc.
Что то не понятен смысл... Что значит "изменение размера с помощью realloc ничем не отличается от delete/new"?! Каким образом new/delete могут перераспределять выделенную память?

Что ты носишься с realloc как с писанной торбой. Уже несколько раз сказали: realloc/malloc/free - это ПЛОХОЙ СТИЛЬ ПРОГРАММИРОВАНИЯ НА С++.
Я не люблю белых пятен в знаниях. Чтобы избегать ошибок, нужно знать к каким последствиям эти ошибки ведут.

P.S. Вот заметил, что часто на разных форумах, когда человек спрашивает совета как "научится плохому", ему обычно отвечают что этому учиться не надо :)
63
10 июня 2007 года
Zorkus
2.6K / / 04.11.2006
Цитата: Gigahard

Что то не понятен смысл... Что значит "изменение размера с помощью realloc ничем не отличается от delete/new"?! Каким образом new/delete могут перераспределять выделенную память?


http://www.cplusplus.com/reference/clibrary/cstdlib/realloc.html
[/QUOTE]

242
11 июня 2007 года
Оlga
2.2K / / 04.02.2006
Цитата:
Что значит "изменение размера с помощью realloc ничем не отличается от delete/new"?! [COLOR=Red]Каким образом new/delete могут перераспределять выделенную память?[/COLOR]

у меня есть сильные подозрения, что таким же образом, что и функция realloc, ответ есть здесь же в топике: http://forum.codenet.ru/showpost.php?p=196743&postcount=22
просто напиши свою функцию, которая при помощи оператора new создает новый массив с нужным размером, переписывает элементы старого массива в него же ну и после этого сохраняет указатель на новый массив в указателе на старый массив, предварительно освободив память, которую он занимал. что-то вроде этого.

350
11 июня 2007 года
cheburator
589 / / 01.06.2006
Сказано же было, юзай возможности std::vector.
1. Вектор писали знающие люди.
2. Вектор реализован на каждой платформе по-своему, его реализовывали те же люди, что писали платформу. Поэтому логично предположить, что он реализован так, чтобы наиболее полно использовать возможности именно данного компилятора, чтобы он компилировался наиболее оптимально для данного компилятора.
3. Я сомневаюсь, что вы, уважаемый начинающий программер, напишете что-то более безопасное и переносимое, нежели std::vector.
4. realloc может выделить память в новом месте, и тогда он просто скопирует содержимое в новое место. Но он не будет вызывать оператор копирования для данного типа (см. сообщение Green'а о безопасности типов: realloc использует void*). А ведь может оказаться, что копирование для данного типа - нетривиально (т. е. просто memcpy не годится). Более того, может оказаться, что наш тип имеет семантику NonCopyable (некопируемый), а realloc тупо побайтно скопирует содержимое, а копирование ведь вообще не разрешено для данного типа, коль скоро он NonCopyable.
5. Для использования new/delete можно выделять немного больше места, чем нужно в данный момент. Т. е. нам нужно сейчас, в данный момент, хранить 28 объектов, а мы выделяем место сразу для 32, имея резерв в 4 лишних объекта.
Для подобных операций C++ предусматривает:
1) Вызов оператора new так, чтобы он не вызывал конструктор. Для этого используйте вместо записи
 
Код:
new MyType
такую запись:
 
Код:
Type::operator new()
Конструктор объекта при этом не вызывается. Для выделения места под массив есть соответствующая конструкция.
2) В момент добавления элемента в массив, в том случае, если имеется уже выделенное и неинициализированное место, используйте опять же оператор new, но уже в "нормальном" виде, но нужно использовать "размещающий" оператор new (такая форма оператора, наоборот, не выделяет место, а лишь вызывает конструктор). Вызов выглядит примерно так:
 
Код:
_type *_object = new (object_ptr) _type(_value)
.
Для уточнения см. http://forum.codenet.ru/showthread.php?t=38979
350
11 июня 2007 года
cheburator
589 / / 01.06.2006
В конце концов, читайте Скотта Майреса или Герба Саттера.
255
11 июня 2007 года
Dart Bobr
1.4K / / 09.04.2004
Цитата: Green
Потому, что ты безвозвратно теряешь инф. о типе.
И проверить корректность восстановления ты не можешь.



Слушай, а что насчет приведения типов?? Это ведь тоже получается информация извне программы. То-есть например у меня есть что-то похожее:

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);
}
}

Я например путей для улучшения такого кода не вижу ((

350
12 июня 2007 года
cheburator
589 / / 01.06.2006
Цитата: Dart Bobr
Слушай, а что насчет приведения типов?? Это ведь тоже получается информация извне программы. То-есть например у меня есть что-то похожее:

int Encrypt(int Length, unsigned char * In, unsigned char * Out);
// немного упрощенно, но пусть будет

Скажем функция эта находится во внешней либе.
А у меня есть переменная:
wchar_t * DecryptedData;
wchar_t * EncryptedData;

Как мне в таком случае обойти конструкцию:

Encrypt((unsigned char *)DecryptedData, (unsigned char *)EncryptedData);



Функция по сути C-шная, и раз уж она находится во внешней библиотеке, ничего не поделаешь.
Но если функцию пишешь сам, используй шаблоны:

 
Код:
template <class Type> int Encrypt (int Length, Type *In, Type *Out)
{
// Код функции
};

Это типобезопасная конструкция, преобразование типов не потребуется.
Цитата: Dart Bobr

или как обойти конструкцию вроде
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 * VeryLargeBuffer;
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.
255
12 июня 2007 года
Dart Bobr
1.4K / / 09.04.2004
а в случае когда нужно инкрементить не на 1?? По-моему
так работать не будет, из-за несоответствия типов:

unsigned char * pBuffer = VeryLargeBuffer;
pBuffer += 0x20;
350
12 июня 2007 года
cheburator
589 / / 01.06.2006
Цитата: Dart Bobr
а в случае когда нужно инкрементить не на 1?? По-моему
так работать не будет, из-за несоответствия типов:

unsigned char * pBuffer = VeryLargeBuffer;
pBuffer += 0x20;



Будет.
Напоминаю правила сложения/вычитания указателей.
К указателю можно прибавить или вычесть любое целое число, это будет расцениваться как "сдвиг" указателя на соответствующее число объектов, на который указывает указатель.
Т. е.

 
Код:
SomeType *pointer = new SomeType[100];
pointer += 50;

После такой операции pointer будет указывать на 50-й элемент массива, каким бы ни был тип SomeType.
К тому же приведенный тобой код
 
Код:
pBuffer = (unsigned char *)((int)VeryLargeBuffer + Offset);

не является безопасным, т. к. при преобразовании VeryLargeBuffer никто не гарантирует, что значение указателя поместится в int, или наоборот, при преобразовании значения ((int)VeryLargeBuffer + Offset) в unsigned char* не гарантируется, что int поместится в указатель. Если в твоем конкретном компиляторе на твоей конкретной ОС размер int'а 32 бит и размер указателя 32 бит, это еще не значит, что на других компиляторах то же самое. Например, в 16-битной MS-DOS компиляторы обычно расценивают int как 16-битное значение, а вот дальний указатель 32-битный.
В крайнем случае надо писать
 
Код:
pBuffer = &VeryLargeBuffer[Offset];

такая запись безопасна.
255
12 июня 2007 года
Dart Bobr
1.4K / / 09.04.2004
спс. за ликбез )
щас буду избавляться от варнингов в прожекте ))
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог