Замена realloc (C → С++)
В более раннем вопросе я спросил о указателях приведения типов, но был направлен на лучшее решение использования системы распределения С++ вместо mallocs. (Я конвертирую некоторый код C в С++)
Однако у меня все еще есть проблема с аналогичной функцией:
Я изменил:
tmp = malloc(sizeof(char*) * mtmp); --> tmp = new char*[mtmp];
и
free(tmp) --> delete [] tmp;
Однако, что мне делать с realloc в следующей функции:
char* space_getRndPlanet (void)
{
int i,j;
char **tmp;
int ntmp;
int mtmp;
char *res;
ntmp = 0;
mtmp = CHUNK_SIZE;
//tmp = malloc(sizeof(char*) * mtmp); <-- replaced with line below
tmp = new char*[mtmp];
for (i=0; i<systems_nstack; i++)
for (j=0; j<systems_stack[i].nplanets; j++) {
if(systems_stack[i].planets[j]->real == ASSET_REAL) {
ntmp++;
if (ntmp > mtmp) { /* need more space */
mtmp += CHUNK_SIZE;
tmp = realloc(tmp, sizeof(char*) * mtmp); <--- Realloc
}
tmp[ntmp-1] = systems_stack[i].planets[j]->name;
Я получаю следующую ошибку:
error: invalid conversion from 'void*' to 'char**'|
ИЗМЕНИТЬ 2:
Хорошо, консенсус, который я получаю, заключается в том, что я должен отказаться от своего текущего решения (которое я открываю для себя).
Чтобы убедиться, что я правильно понимаю, вы, ребята, понимаете, что вместо массива указателей на объекты я должен просто иметь вектор, содержащий сами объекты?
Ответы
Ответ 1
C позволяет void*
неявно преобразовываться в любой указатель. С++ не делает этого, поэтому, если вы используете realloc
, вы должны привести результат к соответствующему типу.
Но что более важно, использование realloc
в указателе, возвращаемом new[]
, - это поведение undefined. И нет никакого прямого С++-стиля, эквивалентного realloc
.
Ваш выбор - от наименьшего до самого идиоматического:
- Придерживайтесь
malloc
/realloc
/free
и нарисуйте указатели.
- Используйте
new[]
+ delete[]
вместо realloc
- Используйте
std::vector<std::string>
вместо управления собственной памятью.
Ответ 2
Кажется, что это ничем не примечательный массив, который растет по мере необходимости.
Прекратите использование явного выделения памяти, вам почти наверняка не нужно этого. Используйте std::vector
или другой из динамических контейнеров стандартной библиотеки С++, которые автоматически растут по мере необходимости для вас.
Также похоже, что вы используете строки C-стиля с нулевым завершением. Почему бы не использовать std::string
вместо этого?
Ответ 3
В С++ вы не должны использовать массивы (даже динамически выделенные).
Это было заменено на std::vector
В C:
char** tmp = (char**)malloc(sizeof(char*) * size);
free(tmp);
// And a correct version of realloc
char** alt = (char**)realloc(sizeof(char*) * newSize);
if (alt)
{
// Note if realloc() fails then it returns NULL
// But that does not mean the original object is deallocated.
tmp = alt;
}
В С++
std::vector<char*> tmp(size);
// No need for free (destructor does that).
tmp.resize(newSize);
Ответ 4
http://www.cplusplus.com/forum/general/18311/
(Короче говоря, на самом деле нет эквивалента С++ для realloc
, но, может быть, вам лучше использовать vector
?)
Ответ 5
Realloc действительно не заботится о вызове конструкторов, поэтому использование realloc после нового похоже на плохую идею. Вы должны использовать вектор в качестве лучшего подхода. Вы можете изменять размер векторов.
Ответ 6
К сожалению, в С++ нет realloc
(из-за того, что память может содержать нетривиально построенные или просто не скопируемые объекты). Либо выделите новый буфер и скопируйте, либо научитесь использовать std::vector
или std::stack
, которые сделают это для вас автоматически.
Ответ 7
Я бы предпочел переключиться с динамического массива, созданного вручную, на вектор хорошего выбора.
Что касается того, должен ли вектор содержать объекты напрямую или содержать указатели на фактические объекты, то нет однозначного ответа - это зависит от ряда факторов.
Самый большой фактор - это то, что я бы назвал объектами "сущность" - те, для которых копирование не имеет смысла. Классическим примером может быть что-то вроде iostream или сетевого подключения. Как правило, нет логического способа копирования или назначения такого объекта. Если это тот объект, с которым вы имеете дело, вы почти застряли в хранении указателей.
Если, однако, вы имеете дело с тем, что обычно (слабо) определено как "объекты значений", копирование и назначение будут прекрасными, а хранение объектов непосредственно в векторе будет в порядке. С такими объектами основной причиной хранения указателей было бы то, что вектор может/будет копировать объекты вокруг, когда он должен расширять память, чтобы освободить место для большего количества объектов. Если ваши объекты настолько велики и дороги для копирования, что это неприемлемо, тогда вы можете захотеть сохранить что-то вроде указателя в векторе, чтобы получить дешевое копирование и назначение. Скорее всего, это не будет сырой указатель, хотя, вероятно, это будет какой-то умный объект-указатель, который обеспечит более ценностную семантику, поэтому большинство других кодов может относиться к объекту как к простому значению, а детали его дорогого операции и т.д. могут оставаться скрытыми.
Ответ 8
Существует не эквивалент С++ realloc().
Наилучшее использование:
char* new_tmp = new (char*)[mtmp];
for (int n=0;n<min(mtmp,oldSize);n++) new_tmp[n] = tmp[n];
delete [] tmp; // free up tmp
tmp = new_tmp;
Ошибка, которую вы получаете, заключается в том, что С++ менее мягкий с неявным типом.