| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Realloc в С++ |
| Автор: sergioK1 6.3.2012, 17:35 |
| Слышу что плохо , а в чем ?, ну есть вектор, ну он же не вместо realloc, по крайне мере в доках никто не говорит что он лучше, Или Я чего не понимаю? |
| Автор: borisbn 6.3.2012, 18:58 |
1) Как минимум realloc не типизирован (читай увеличивается вероятность ошибки). 2) Вместе с указателем на память, выделенную malloc/realloc неплохо бы хранить выделенный размер. У вектора это есть нахаляву 3) При удалении вектора он сам следит за освобождением выделенной им памяти, в случае с malloc/realloc программист должен не забыть вызвать free когда память больше не нужна на самом деле пунктов больше... я тебе только основные привёл |
| Автор: bsa 6.3.2012, 20:47 |
| самый главный забыл. если у тебя объекты содержат ссылки/указатели на другие объекты в том же массиве, то после realloc возможна ситуация, что размещение массива в памяти изменится, а вот указатели/ссылки внутри объектов нет. В итоге это приведет к серьезным ошибкам. Именно поэтому в С++ realloc нежелателен. |
| Автор: sergioK1 7.3.2012, 01:12 | ||
как это измениться ? man 3 realloc void *realloc(void *ptr, size_t size); realloc() changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If ptr is NULL, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done. где тут сказано про то что размешение измениться ,? borisbn для стандартных задач это хорошо, ну а если свой вектор нужен , самое простое перед функцией resize - запись в лог, или мютекс ,? и есть типы обьестов которые надо закрыть ? то наследовать? обертку писать ? ну тогда твой класс должен быть темплайтным , У меня свой контейнер , и Я счас не знаю что лучше realloc или новый malloc + memcpy + заполнение второй части данными, Я с этим столькнулся в 99 году на чистом С(Win32), realloc из-за падал и пришлось менять логику что-бы без него , там что то обьяснялось ,только Я не помню С тех пор наверно что-то изменилось ? |
| Автор: volatile 7.3.2012, 01:58 | ||
sergioK1, Как вы себе вообще это представляете? Произвольное изменение размера, непрерывного участка памяти ?
http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/ |
| Автор: sergioK1 7.3.2012, 04:42 | ||||
Xm почему в доке Линукса ничего про это не сказано ? хотя простой тест показал что это так, чего то Я не понимаю, блок памяти передвиниться а ссылки эти разве не в нем? , т,е элемент массива это стуктура , где первый элемент это его начало , и все ссылки внутри что с ними будет ? если скажем первый элемент массива имеет ссылку на скажем 8-ой тогда да realloc даст сбой , но в каком случае, изначально создавать такой массив архитектурная ошибка IMHO, или задача специфичная, и потом элементы могут меняться , кто за ссылками следить будет ? да и какая разница С или С++? |
| Автор: borisbn 7.3.2012, 06:19 |
| >обертку писать ? ну тогда твой класс должен быть темплайтным Абсолютно ничего плохого здесь не вижу. >да и какая разница С или С++? тут 2 момента: 1) ты задал вопрос именно про Си++ 2) в Си просто нет вектора, new/delete и т.п., поэтому в Си кроме realloc'а ничего и не остаётся. |
| Автор: Dem_max 7.3.2012, 06:22 |
| в С++ есть только new и delete. |
| Автор: LeonidPr 7.3.2012, 07:10 | ||||
http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/
|
| Автор: bsa 7.3.2012, 10:21 | ||
Вообще-то вектор копирует содержимое не с помощью memcpy, а с использованием операторов копирования. Поэтому, если класс более или менее вменяемый, то он это дело сам разрулит. |
| Автор: sergioK1 7.3.2012, 11:30 | ||||||
Да нет, Я говорю не про вектор , это отдельная тема , Случайно ++ добавил , Я про realloc vs новый malloc c переписыванием всего старого массива в новый , т,е, способ 1
или
вместо int* могут быть обьекты AnyClass* object , разница тоько что в С++ typedef не нужен и в С есть только Struct. т,е, чем плохо Я имел ввиду разницу между этими способами, какая разница С или С++? bsa : какая разница что оператор копирования ,это тот же memcopy, только скрыиый, релизации на все равно на асемблере , другово еще не придумали |
| Автор: xvr 7.3.2012, 15:40 |
Оператор копирования - это operator =() и копируемый класс его может переопределить, если это надо (а это часто надо) Как все запущено |
| Автор: sergioK1 7.3.2012, 17:00 | ||
Это как бы все знают , И что , это всего лишь для удобсва , легче писать , А как он реализован? И чем скомилированный код с ним отличаеться от того что без ? |
| Автор: xvr 7.3.2012, 17:10 | ||
Отличаться может координально. Вплоть до того, что memcpy работать для данного класса не будет, а operator =() будет. Например:
Без operator=() этот класс после копирования начнет дописывать строки к оригиналу (откуда копировали), а не к себе. |
| Автор: feodorv 7.3.2012, 17:35 | ||||
Бог ты мой, да в C те же проблемы. Если, скажем, внутри одной структуры определяются указатели на какие-то значения этой структуры, то беды при realloc не избежать:
И ещё пример. Здесь просто запомнили указатель на какой-то элемент списка, а потом сделали realloc:
Примеры выдуманы, но они демонстрирует опасный код, связанный с realloc. Такие ситуации лечатся тем, что нужно хранить не указатели, а смещения. Но от ошибок никто не застрахован... |
| Автор: sergioK1 7.3.2012, 17:40 | ||||||
что измениться есть вместо operator = будет метод Сlone ? а operator = будет private , для верности , а на С = просто не вызывать, да писать так не очень удобно , но компайлеру то какая разница ,?
|
| Автор: bsa 7.3.2012, 17:50 |
C отличается от С++ тем, что на тебе лежит больше обязанностей по контролю правильности. Изменится то, что стандартные методы работать с таким классом не будут. Зачем усложнять себе жизнь? |
| Автор: sergioK1 7.3.2012, 21:20 | ||
Или писать свой wrapper realloc он же Clone и копировать указатели/ссылки , или не копировать , в зависимости от задачи, в С++ это копи конструктор , но это не значит что realloc это плохо, в случае с vector возникают теже самые проблемы , feodorv - спасибо прояснил ситуацию , Вопрос решен |
| Автор: xvr 8.3.2012, 09:37 | ||
Разница в том, что operator= будет вызываться автоматически компилятором (там, где надо), а Clone вам придется звать вручную. При этом запросто можно забыть и не позвать этот самый Clone (человеку свойственно ошибаться). А вот компилятор не ошибается. Ну и в конце концов у вас может и не быть возможности этот самый Clone позвать (как уже упоминал bsa, например при использовании stl контейнеров) PS. В 99% реализации realloc внутри сделает free и malloc если его попросят увеличить выделенный блок, так что его использование не дает никаких преимуществ |
| Автор: sergioK1 8.3.2012, 10:20 | ||
На чем это утверждение основано ? мне как в суде аргуметы нужны и факты |
| Автор: Alexeis 8.3.2012, 11:03 |
Потому же менеджер кучи не резервирует дополнительного места после блока выделенной памяти. Расширение будет только если освободили память строго за текущим блоком при этом освобожденный блок был больше чем нужно для роста. Такое событие маловероятно. Если хотите реально иметь возможность выделять память с возможностью роста, то такое поведение можно сделать средствами ОС, в частности в Windows можно зарезервировать адресное пространство, но выделить только столько сколько нужно, а при необходимости до выделить память по зарезервированным адресам. Тогда получиться непрерывный кусок расширяемый кусок. |
| Автор: sergioK1 8.3.2012, 11:36 | ||
Это понятно ,но Я не уверен что он вызывает имеено malloc , если бы так то realloc был бы не нужен , а не другие механизмы , более низнего уровня, |
| Автор: bsa 8.3.2012, 14:28 | ||
malloc/realloc/calloc/free работают с "кучей" (new/delete тоже, кстати), которая реализуется средствами стандартной библиотеки. К API системы это не имеет отношения (точнее, API используется только для изменения размеров собственно кучи). А куча - это как файловая система на диске, только без возможности фрагментации. Увеличить конкретный блок можно только: или если после него есть свободное место или если он находится в конце кучи, а другого подходящего куска в куче нет, в этом случае куча будет увеличена и блок будет увеличен соответственно. |
| Автор: xvr 9.3.2012, 10:06 |
На изучении некоторого количества сорцов RTL и на здравом смысле. Если вы хотите, что бы realloc мог сделать что то помимо free/malloc вам надо самому следить за тем, что и в какой последовательности вы просите расположить на куче. realloc не может перераспределить уже выделенную память, поэтому, если после куска, который вы хотите увеличить, что то уже лежит, то никаких вариантов кроме free/malloc уже не остается |
| Автор: sergioK1 10.3.2012, 17:53 | ||
Не понял, если если после куска, который вы хотите увеличить, что то уже лежит, то логике ,realloc сам вызовет malloc + memcpy, или какой то свой механизм/алгоритм, Я ж не знаю лежит что-то после куска или нет , счас может лежать через 5 минут нет , про самому следить за тем, что и в какой последовательности вы просите расположить на куче это как ? |
| Автор: bsa 10.3.2012, 18:33 | ||||
Написать свой собственный менеджер кучи. |
| Автор: sergioK1 12.3.2012, 00:01 | ||
| он и в С не особо то и нужен, все равно нужно клонировать объект (хоть с =() , хоть и без ), тут вопрос закрыт еще момент , раз уж зашла речь за вектор ,
стандартный вектор на два множит , мне надо 100 прибавлять, правильно алокатор писать ? должен быть свой класс наследник std::allocator? , какие методы перегружать ? или у вектора resize перегрузить ? |
| Автор: xvr 12.3.2012, 08:48 |
Вектор имеет право изменять размер буфера как ему захочется, но снаружи это не видно. size() всегда будет возвращать размер реальных данных. А вот capacity() будет возвращать нечто большее. Это не поможет, вектор стартегию выделения памяти (с запасом) на allocator не отдает. Управляйте размером и резервацией в векторе явно (resize() и reserve()) Никакие. У STL контейнеров нет виртуальных методов |
| Автор: mes 12.3.2012, 09:20 |
из простого, написать свой (внешний) push_back, который будет ресайзить по нужной стратегии... |
| Автор: sergioK1 12.3.2012, 09:26 | ||
как это будет на С++ не словах, mess , как ?, внутри вектора есть обьест, который при добавке умножает память на 2, как мне этот обьект получить ? пример если не трудно положите |
| Автор: mes 12.3.2012, 10:38 | ||
mes
самого вектора достаточно.. http://liveworkspace.org/code/ba491fe1c0f7be196622e759b9282854 |
| Автор: xvr 12.3.2012, 13:17 | ||
|
| Автор: volatile 13.3.2012, 02:09 |
| В векторе же не только пуш-бек, добавлять может там еще придется "костылировать"... Добавлено через 3 минуты и 54 секунды sergioK1, вам имхо нужен не вектор. рассмотрите возможность использования deque. |
| Автор: sergioK1 13.3.2012, 12:18 | ||
там еще придется "костылировать" А это на каком языке ? Alocator для чего? только не говорите что мне он не нужен (так многие говорят, и пугают им как бабой ягой как с ним работать? , примерчик если не сложно |
| Автор: xvr 13.3.2012, 13:11 |
Для выделения/удаления памяти и инициализации объектов на ней. Стандартный Allocator аналогичен связке из new/delete и конструктора и деструктора для произвольного класса (для этого там используются шаблонные функции). Свой Allocator нужен если вы хотите изменить стандартный менеджер памяти для конкретных экземпляров контейнера (например сделать память на пуле, а не в куче) На внутреннее функционирование контейнеров Allocator не влияет Добавлено через 43 секунды На С++ - std::deque<> - стандартный контейнер |
| Автор: sergioK1 13.3.2012, 14:02 |
| 1) Что значит фраза из предыдушего поста , "там придеться костылить" 2) разницу между деком и вектором не понимаю , дока пишеть что more efficient , видимо доступ вместо O(n) O(log2) или O(1) , ну и инсерт хуже соответсвенно , методы у обоих класов одинаковые, а что там мор когда и на сколько?, |
| Автор: bsa 13.3.2012, 21:57 | ||
sergioK1,
|
| Автор: volatile 14.3.2012, 03:13 | ||
то что, в вектор добавлять придется не стандартной процедурой: vector.push_back (element); а костылем: my_push_back (vector, element); Кроме-то в вектор могут добавлять и другие методы. Их тоже нужно переписывать. Извиняюсь за придуманное слово "костылировать" Насчет дека, добалю к тому что сказал bsa, у него есть один недостаток, по сравнению с вектором: Данные расположены не непрерывно. Второй недостаток это несколько медленное время доступа к центральным элементам. (По опыту скажу, не на много медленее, по крайней мере в студии) Преимущества: Выделят блоки примерно так как вы хотите, порциями. Все прежде выделенные блоки остаются на своих местах, никаких гигантских перераспределений памяти (как в векторе) не бывает. Вообще ведет себя довольно ровно, в отличии от вектора. Последний, при достаточном размере, может в буквальном смысле подвесить программу на n-ое кол-во секунд, с требованиями трехкратного запаса памяти. Как это происходит: Допустим вектор имеет размер 1000, постпупил еще 1 элемент, в этот момент он затребует 2000 памяти, (1000+2000=3000), потом откопирует, и только потом освободит 1000. То есть, есть момент когда нужен 3-кратный запас по памяти. Кстати, в вашем случае с my_push_back(), нужен будет 2 кратный+100 запас (1000+1100=2100), но и перераспределения будут происходить чаще. |
| Автор: sergioK1 14.3.2012, 12:39 | ||
Так Deck - это получаеться линк лист где вместо нода массив каждый раз разного размера где последний елемент , указывает на первый в следующем , т,е в сранение с просто линк листом , доступ к елеметам внутри блока будет О(1)(по индексу), т,е у линк листа это всегдаO(n) а в деке как , зная размер каждого блока , сразу будет искать в нужном , ? т,е O(average(blockSize) , т,е, при вызове скажем D[5296] он знает что надо пойти в 38 блок , а там все 150 элеметов, но это если данные порциями приходят, скажем по 50 элеметов в среднем , но если придут по 5 то это мало что даст, т,е, в плане выделения памяти он ведет себя как линк лист в плане доступа как обычный массив, т,е применять его можно когда четко знаешь что у тебя за данные , Кажеться сам себе ответил да еще Так тут не один способ релизаций может быть , у каждого поставщика компайлера свой, а вектор (если нельзя изменить *2 ) это зло наверняка есть либы где , push back и resize виртуальные , или Я чего пропустил , |
| Автор: mes 14.3.2012, 21:38 |
это используется для неизвестного кол-ва данных.. Если есть предположения о кол-ве входящих данных, то нужна своя стратегия увелечения данных.. Более того бывают случаи, когда удобно пользоваться не одним типом контейнера, а смешанным в зависимости от подзадачи.. Например считать данные в деку, чтоб избежать лишнего копирования при перераспределении, а после поместить все в вектор уже нужного размера, чтоб иметь возможность прямого доступа.. |
| Автор: sergioK1 14.3.2012, 22:41 |
Все ясно всем спасибо, выяснил даже больше чем хотел, закрываем лавочку |
| Автор: bsa 19.3.2012, 13:27 | ||
deque (от double ended queue - двусторонняя очередь) это примерно вектор указателей на фиксированные вектора. Т.е. когда ты добавляешь в дек данные, а у него нет под них места, то выделяется блок данных фиксированного размера, и в него уже добавляются данные. Указатель на свежевыделенный блок попадает в вектор указателей. Для вычисления элемента по индексу достаточно ему выполнить: ptr_vector[idx / blk_data_size][idx % blk_data_size]; Как ты понимаешь, время константно. |
| Автор: sergioK1 19.3.2012, 15:33 | ||||
Понимаю , сам такое когда-то изобретал на С , Реализацию где посмотреть ? от поставщика , |
| Автор: bsa 19.3.2012, 16:10 |
| sergioK1, начни с хидера deque. А дальше уже тебя IDE направит. |
| Автор: sergioK1 19.3.2012, 23:33 | ||
OK, смотрю thanks |