2010-10-06 9 views
10

In una domanda precedente, ho chiesto informazioni sui puntatori di typecasting, ma è stato indirizzato alla soluzione migliore di utilizzare il sistema di allocazione C++ anziché mallocs. (I sono la conversione del codice C al C++)Sostituzione di realloc (C -> C++)

Tuttavia, ho ancora un problema con una funzione simile:

ho cambiato:

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

e

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

Tuttavia, cosa devo fare con realloc nella seguente funzione:

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; 

Sto ottenendo il seguente errore:

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

EDIT 2:

D'accordo, il consenso sto ottenendo è che dovrei abbandonare la mia soluzione attuale (che io sono aperto a fare).

Giusto per essere sicuro di comprendere correttamente, voi ragazzi intendete che, invece di una serie di puntatori agli oggetti, dovrei semplicemente avere un vettore contenente gli oggetti stessi?

+1

Ben ignorando il fatto che si sta utilizzando realloc() in modo non corretto nella parte di codice precedente. Questo è un punto debole del C++ causato dal fatto che gli oggetti hanno costruttori/distruttori. Il problema viene risolto utilizzando il vettore piuttosto che gli array raw. –

risposta

14

C consente di convertire implicitamente void* in qualsiasi puntatore. C++ no, quindi se stai usando realloc, devi trasmettere il risultato al tipo appropriato.

Ma ancora più importante, l'utilizzo di realloc su un puntatore restituito da new[] è un comportamento non definito.E non esiste uno stile C++ diretto equivalente a realloc.

Le scelte sono, dal meno al più idiomatica:

  • Stick per malloc/realloc/free e gettano i puntatori.
  • Usa new[] + delete[] invece di realloc
  • Uso std::vector<std::string> invece di gestire la propria memoria.
+1

Inoltre non dovresti mixare new/delete e malloc/calloc/realloc/allocazione di memoria libera. – PaulMcG

+1

Tecnicamente dovresti usare 'delete []' con 'new []'. – Derek

2

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

(In breve - non c'è davvero un C++ equivalente a realloc, ma forse si sarebbe meglio di utilizzare un vector?)

+0

Potresti spiegarmi che cosa esattamente realloc sta facendo qui? Inoltre, sostituendo la soluzione corrente con i vettori ciò significa che, invece di una pila, sto usando un dispositivo simile ad una matrice (cioè il vettore). I.e: questo significa che dovrei sostituire la soluzione di stack corrente? – Biosci3c

+0

@ Biosci3c Puoi anche usare una pila quindi. C++ definisce entrambi i tipi nella libreria di template standard. Vedi http: //www.cplusplus.it/reference/stl/ – zneak

+1

@ Biosci3c - realloc sta creando uno spazio di memoria più grande per contenere il contenuto di ciò che c'è in 'tmp', perché il vecchio spazio era pieno. I contenitori ridimensionabili del C++ lo fanno automaticamente per te. Puoi usare uno 'stack' o un' vector'; entrambi supportano operazioni "stack-like" (ma il 'vector' supporta anche l'accesso casuale, mentre lo' stack' non lo fa). – Amber

-1

Non v'è alcun C equivalente ++ di realloc().

Miglior 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; 

L'errore che si sta ottenendo è causa C++ è meno indulgente con il casting di tipo implicito.

+1

Non è l'uso migliore: l'idea di 'realloc' è di conservare il contenuto della memoria. –

+1

Se si desidera eseguire l'allocazione manuale della memoria, è necessario allocare la nuova memoria, quindi copiare i contenuti nella memoria appena allocata. Solo dopo che entrambi hanno avuto successo dovresti eliminare la vecchia memoria. –

1

Purtroppo non c'è lo realloc in C++ (poiché la memoria potrebbe contenere oggetti non banali o solo non copiabili). Assegna un nuovo buffer e copia o impara a usare std::vector o std::stack per farlo automaticamente.

13

Questo sembra essere un array insignificante che cresce all'occorrenza.

Interrompere l'utilizzo di allocazione di memoria esplicita, quasi certamente non ce n'è bisogno. Usa std::vector o un altro contenitore dinamico della libreria standard C++ che cresce automaticamente secondo le tue necessità.

Sembra anche che tu stia usando stringhe in stile C con terminazione nulla. Perché non usato invece std::string?

+0

Sto convertendo un vecchio codice C e imparando mentre vado (non ho familiarità con C molto, solo C++). Quindi questo potrebbe funzionare. – Biosci3c

2

Realloc non si preoccupa davvero di chiamare i costruttori, quindi l'utilizzo di realloc dopo il nuovo sembra una cattiva idea. Si dovrebbe scegliere il vettore come approccio migliore. È possibile ridimensionare i vettori.

5

In C++ non si dovrebbero utilizzare matrici (anche allocate dinamicamente).

Questo è stato sostituito con 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); 
1

avrei considerazione il passaggio dalla matrice dinamica artigianale ad un vector una buona prima scelta.

Per quanto riguarda la possibilità che il vettore contenga oggetti direttamente o contenga puntatori agli oggetti effettivi, non esiste un'unica risposta definitiva, dipende da un numero di fattori.

Il singolo più grande fattore è se questi sono quelli che chiamerei oggetti "entità" - quelli per i quali la copia non ha senso. Un classico caso in questione sarebbe qualcosa come un iostream o una connessione di rete. In genere non esiste un modo logico per copiare o assegnare un oggetto come questo. Se questo è il tipo di oggetto con cui hai a che fare, sei praticamente bloccato nei puntatori.

Se, tuttavia, si ha a che fare con ciò che generalmente (in modo approssimativo) viene definito come "oggetti valore", la copia e l'assegnazione andranno bene e la memorizzazione degli oggetti direttamente nel vettore andrà bene. Con oggetti come questo, la ragione principale per archiviare i puntatori sarebbe che un vettore può/copierà gli oggetti quando deve espandere la memoria per fare spazio a più oggetti. Se i tuoi oggetti sono così grandi e costosi da copiare che questo è inaccettabile, allora potresti voler memorizzare qualcosa come un puntatore nel vettore per ottenere copie e assegnazioni a basso costo. È probabile che sia non essere un puntatore non elaborato - probabilmente sarà una sorta di oggetto puntatore intelligente che fornisce semantica più di valore in modo che la maggior parte degli altri codici possa considerare l'oggetto come un valore semplice e i dettagli di le sue operazioni costose e tali possono rimanere nascoste.