Замена 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;

Ошибка, которую вы получаете, заключается в том, что С++ менее мягкий с неявным типом.