2010-10-06 41 views
10

En una pregunta anterior, pregunté acerca de los punteros de conversión de tipos, pero se me remitió a la mejor solución de utilizar el sistema de asignación C++ en lugar de mallocs. (Estoy convirtiendo algo de código C a C++)Reemplazo de realloc (C -> C++)

Sin embargo, todavía tengo un problema con una función similar:

me cambió:

tmp = malloc(sizeof(char*) * mtmp); --> tmp = new char*[mtmp]; 

y

free(tmp) --> delete [] tmp; 

Sin embargo, ¿Qué debo hacer con realloc en la siguiente función:

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; 

estoy consiguiendo el error siguiente:

error: invalid conversion from 'void*' to 'char**'| 

EDIT 2:

acuerdo, el consenso que estoy recibiendo es que debo abandonar mi solución actual (que estoy abierto a hacer).

Solo para asegurarme de que estoy entendiendo correctamente, ¿quieren decirme que, en lugar de una serie de punteros a los objetos, debería tener un vector que contenga los objetos mismos?

+1

Ignorando bien el hecho de que está utilizando realloc() incorrectamente en el fragmento de código anterior. Esta es una debilidad de C++ causada porque los objetos tienen constructores/destructores. El problema se resuelve mediante el uso de vectores en lugar de matrices en bruto. –

Respuesta

14

C permite convertir implícitamente void* a cualquier puntero. C++ no, por lo que si usa realloc, debe convertir el resultado al tipo apropiado.

Pero más importante aún, usar realloc en un puntero devuelto por new[] es un comportamiento indefinido.Y no hay un estilo directo de C++ equivalente a realloc.

Las opciones son, de menos a más idiomática:

  • adhieren a malloc/realloc/free y echaron los punteros.
  • Uso new[] + delete[] en lugar de realloc
  • Uso std::vector<std::string> en lugar de la gestión de su propia memoria.
+1

Además, no debe mezclar la asignación de memoria new/delete y malloc/calloc/realloc/free. – PaulMcG

+1

Técnicamente debería usar 'delete []' con 'new []'. – Derek

2

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

(En pocas palabras - no hay realmente un C++ equivalente a realloc, pero quizá sería mejor de usar un vector?)

+0

¿Podría explicarme qué hace exactamente realloc aquí? Además, al reemplazar la solución actual con vectores, esto significa que, en lugar de una pila, estoy usando un dispositivo similar a una matriz (es decir, un vector). Es decir: ¿significa esto que debería reemplazar la solución de pila actual? – Biosci3c

+0

@ Biosci3c También puedes usar una pila entonces. C++ define ambos tipos en la biblioteca de plantillas estándar. Ver http: //www.cplusplus.com/reference/stl/ – zneak

+1

@ Biosci3c - realloc está creando un espacio de memoria más grande para contener los contenidos de lo que está en 'tmp', porque el espacio anterior estaba lleno. Los contenedores re dimensionables de C++ lo hacen automáticamente por usted. Puedes usar 'stack' o' vector'; ambos admiten operaciones "apilables" (pero el 'vector' también admite acceso aleatorio, mientras que' stack' no). – Amber

-1

No hay equivalente en C++ de realloc().

Mejor uso:

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; 

El error que está recibiendo es debido a que C++ es menos indulgente con la fundición de tipo implícito.

+1

No es el mejor uso: la idea de 'realloc' es retener el contenido de la memoria. –

+1

Si insiste en realizar la asignación de memoria manual, debe asignar la nueva memoria y luego copiar el contenido en la memoria recientemente asignada. Solo después de que ambos tengan éxito debería eliminar la memoria anterior. –

1

Desafortunadamente no hay realloc en C++ (debido a que la memoria puede contener objetos no triviales o simplemente no copiables). Asigne un nuevo buffer y copie o aprenda a usar std::vector o std::stack que lo haría por usted automáticamente.

13

Esto parece ser una matriz sin complicaciones que crece según sea necesario.

Deje de usar la asignación de memoria explícita, casi seguro que no la necesita. Use std::vector u otro de los contenedores dinámicos de la biblioteca estándar de C++ que crece automáticamente según lo necesite.

También parece que está usando cadenas de estilo C con terminación nula. ¿Por qué no se usa std::string en su lugar?

+0

Estoy convirtiendo algunos viejos códigos C, y aprendiendo sobre la marcha (no estoy familiarizado con C mucho, solo con C++). Entonces esto podría funcionar. – Biosci3c

2

A Realloc realmente no le interesan los constructores de llamadas, por lo que usar realloc después de nuevo parece ser una mala idea. Deberías utilizar el vector como un mejor enfoque. Puedes cambiar el tamaño de los vectores.

5

En C++ no debería estar utilizando matrices (incluso dinámicamente asignadas).

Esto ha sido reemplazado con std :: vector

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

En C++

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

// No need for free (destructor does that). 
tmp.resize(newSize); 
1

me gustaría considerar el cambio de la matriz dinámica hechos a mano a una vector una buena primera opción.

En cuanto a si el vector debe contener objetos directamente, o contener punteros a los objetos reales, no hay una sola respuesta definitiva, depende de una serie de factores.

El factor más importante es si esto es lo que yo llamaría objetos de "entidad", para los que la copia no tiene sentido. Un caso clásico en cuestión sería algo así como una iostream o una conexión de red. Generalmente no hay una forma lógica de copiar o asignar un objeto como este. Si ese es el tipo de objeto con el que estás lidiando, estás bastante atrapado almacenando punteros.

Si, sin embargo, se trata de lo que generalmente (vagamente) se define como "objetos de valor", copiar y asignar estará bien, y el almacenamiento de los objetos directamente en el vector estará bien. Con objetos como este, la razón principal para almacenar punteros sería que un vector puede/copiará objetos cuando tenga que expandir la memoria para dejar espacio para más objetos. Si sus objetos son tan grandes y caros de copiar que esto es inaceptable, entonces es posible que desee almacenar algo parecido a un puntero en el vector para obtener copias y asignaciones baratas. Lo más probable es que no sea un puntero sin procesar, probablemente sea algún tipo de objeto de puntero inteligente que proporcione más semántica de valor, de modo que la mayoría del otro código pueda tratar el objeto como un valor simple, y los detalles de sus costosas operaciones y tal pueden permanecer ocultas.