Замена realloc (C --> C++)

В более раннем вопросе я спрашивал об указателях приведения типов, но был направлен на лучшее решение с использованием системы распределения C++ вместо mallocs. (Я преобразовываю некоторый код C в 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:

Хорошо, консенсус, который я получаю, заключается в том, что я должен отказаться от своего текущего решения (что я готов сделать).

Чтобы убедиться, что я правильно понимаю, вы, ребята, имеете в виду, что вместо массива указателей на объекты у меня должен быть просто вектор, содержащий сами объекты?


person Biosci3c    schedule 06.10.2010    source источник
comment
Ну, игнорируя тот факт, что вы неправильно используете realloc() в приведенном выше фрагменте кода. Это слабость C++, вызванная тем, что у объектов есть конструкторы/деструкторы. Проблема решается использованием векторных, а не необработанных массивов.   -  person Martin York    schedule 06.10.2010


Ответы (8)


C позволяет неявно преобразовывать void* в любой указатель. C++ этого не делает, поэтому, если вы используете realloc, вы должны привести результат к соответствующему типу.

Но что более важно, использование realloc для указателя, возвращаемого new[], является поведением undefined. И нет прямого эквивалента стиля C++ для realloc.

Ваш выбор, от наименее до наиболее идиоматичного:

  • Придерживайтесь malloc/realloc/free и указывайте указатели.
  • Используйте new[] + delete[] вместо realloc
  • Используйте std::vector<std::string> вместо управления собственной памятью.
person dan04    schedule 06.10.2010
comment
Кроме того, вы не должны смешивать выделение памяти new/delete и malloc/calloc/realloc/free. - person PaulMcG; 06.10.2010
comment
Технически вы должны использовать delete[] с new[]. - person Derek; 23.05.2013

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

Прекратите использовать явное выделение памяти, оно вам почти наверняка не нужно. Используйте std::vector или другой динамический контейнер стандартной библиотеки C++, который автоматически увеличивается по мере необходимости.

Также похоже, что вы используете строки в стиле C с нулевым завершением. Почему бы не использовать std::string вместо этого?

person Nicholas Knight    schedule 06.10.2010
comment
Я конвертирую старый код C и учусь по ходу дела (не очень хорошо знаком с C, просто C++). Так что это может сработать. - person Biosci3c; 06.10.2010

В С++ вы не должны использовать массивы (даже динамически распределенные).

Это было заменено на std::vector

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

In C++

std::vector<char*>   tmp(size);

// No need for free (destructor does that).
tmp.resize(newSize);
person Martin York    schedule 06.10.2010

http://www.cplusplus.com/forum/general/18311/

(Короче говоря, на С++ нет эквивалента realloc, но, может быть, вам лучше использовать vector?)

person Amber    schedule 06.10.2010
comment
Не могли бы вы объяснить мне, что именно здесь делает realloc? Кроме того, замена текущего решения векторами означает, что вместо стека я использую устройство, подобное массиву (т.е. вектор). То есть: означает ли это, что я должен заменить текущее решение стека? - person Biosci3c; 06.10.2010
comment
@ Biosci3c Тогда вы также можете использовать стек. C++ определяет оба типа в стандартной библиотеке шаблонов. См. cplusplus.com/reference/stl. - person zneak; 06.10.2010
comment
@ Biosci3c - realloc создает больший объем памяти для хранения содержимого того, что находится в tmp, потому что старое пространство было заполнено. Контейнеры C++ с изменяемым размером делают это автоматически. Вы можете использовать stack или vector; оба они поддерживают операции, подобные стеку (но vector также поддерживает произвольный доступ, а stack — нет). - person Amber; 06.10.2010
comment
Кроме того, в вашем текущем решении tmp - это не стек, а массив. - person Amber; 06.10.2010
comment
Realloc попытается изменить размер текущего выделенного блока памяти. Если это невозможно (скажем, вы пытаетесь увеличить его, а на пути есть еще один блок), он выделит новый блок памяти, скопирует содержимое указателя и вернет новый указатель на структуру. (Исходный указатель не изменится, если вы этого не сделаете). Учитывая природу объектов в C++ (например, глубокое копирование или поверхностное копирование), такая логика должна обрабатываться пользователем, поскольку компилятор не может знать, как что-то нужно копировать. - person Kyte; 06.10.2010

Realloc на самом деле не заботится о вызове конструкторов, поэтому использование realloc после new кажется плохой идеей. Вам следует выбрать вектор как лучший подход. Вы можете изменить размер векторов.

person Alok Save    schedule 06.10.2010

К сожалению, в С++ нет realloc (из-за того, что в памяти могут храниться нетривиально созданные или просто некопируемые объекты). Либо выделите новый буфер и скопируйте, либо научитесь использовать std::vector или std::stack, которые сделают это за вас автоматически.

person Nikolai Fetissov    schedule 06.10.2010

Я бы счел переход от созданного вручную динамического массива к вектору хорошим первым выбором.

Что касается того, должен ли вектор содержать объекты напрямую или содержать указатели на реальные объекты, однозначного ответа нет — это зависит от ряда факторов.

Единственным важным фактором является то, являются ли они тем, что я бы назвал объектами-сущностями, для которых копирование не имеет смысла. Классическим примером может быть что-то вроде iostream или сетевого подключения. Как правило, нет логического способа скопировать или присвоить объект, подобный этому. Если это объект, с которым вы имеете дело, вы в значительной степени застряли в хранении указателей.

Однако, если вы имеете дело с тем, что обычно (в общих чертах) определяется как «объекты-значения», копирование и присваивание будут в порядке, а хранение объектов непосредственно в векторе будет в порядке. С такими объектами основной причиной хранения указателей вместо этого будет то, что вектор может/будет копировать объекты, когда ему нужно расширить память, чтобы освободить место для большего количества объектов. Если ваши объекты настолько велики и дороги для копирования, что это неприемлемо, то вы можете захотеть сохранить что-то вроде указателя в векторе, чтобы получить дешевое копирование и присваивание. Скорее всего, это будет не необработанный указатель — это, вероятно, будет какой-то объект интеллектуального указателя, который обеспечивает семантику, более похожую на значение, поэтому большинство других кодов может рассматривать объект как простое значение. , а детали его дорогостоящих операций и тому подобное могут оставаться скрытыми.

person Jerry Coffin    schedule 06.10.2010

В C++ нет эквивалента 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;

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

person Alexander Rafferty    schedule 06.10.2010
comment
Не лучшее использование - идея realloc состоит в том, чтобы сохранить содержимое памяти. - person Nikolai Fetissov; 06.10.2010
comment
Если вы настаиваете на ручном выделении памяти, вам следует выделить новую память, а затем скопировать содержимое во вновь выделенную память. Только после того, как оба они преуспеют, вы должны удалить старую память. - person Jerry Coffin; 06.10.2010