2009-12-18 12 views
8

Sto indagando su una perdita di memoria e da quello che vedo, il problema si presenta in questo modo:C++ l'allocazione dinamica della memoria in una funzione - domanda newbie

int main(){ 
    char *cp = 0; 
    func(cp); 
    //code 
    delete[] cp; 
} 

void func(char *cp){ 
    cp = new char[100]; 
} 

il codice // commento, mi aspettavo cp a puntare alla memoria allocata, ma è ancora un puntatore nullo che significa che non ho mai eliminato la memoria. Cosa sto facendo Wroing?

+1

Presumo che 'cbuf' supponesse di essere' cp'? – GManNickG

+0

che ne dici di posizionare il codice reale. A meno che il codice non sia tagliato e incollato, è possibile aggiungere errori. Questo rende solo più difficile e ci finiamo per risolvere errori tagliati e paster come cbuf -> cp –

+0

Scusaci, lo terrò a mente per la prossima volta. Sì cbuf doveva essere cp –

risposta

11
void func(char *cp){ 
    cp = new char[100]; 
} 

In questa funzione, char * cp è un "puntatore essere passato da copia" ciò significa che essi puntano allo stesso indirizzo di memoria ma non sono lo stesso puntatore . Quando si modifica il puntatore all'interno, rendendo al punto da qualche altra parte, il puntatore originale che è stata passata manterrà punta a 0.

+0

Grazie, risolto bene. Spiegazione molto chiara –

+0

@David: Grazie :) –

6

Il parametro cp è una variabile locale della funzione - la modifica di esso non modifica nulla al di fuori della funzione. Un modo migliore per scrivere la funzione è:

char * func(){ 
    return new char[100]; 
} 

E non a che fare direttamente con la tua domanda, ma probabilmente si dovrebbe utilizzare std :: string e std :: vector, piuttosto che le matrici allocate in modo dinamico.

+1

Hmm, due downvotes. Non che mi interessi in modo particolare, ma altri potrebbero trarre beneficio dal sapere cosa c'è di sbagliato in questa risposta. –

+0

Nulla che io possa vedere. Se stai per indicare qualcosa come le funzionalità di C++ che hai menzionato, penso che sia probabilmente utile aggiungere una parte relativa alla non codifica della dimensione dell'array. Inoltre, se hai intenzione di usare quelle caratteristiche particolari, probabilmente vorrai passare un puntatore a uno in base a un riferimento per crearlo, oppure passarne uno già creato in base al riferimento per evitare la penalità del costruttore di copie ... ma non c'è davvero nulla di sbagliato con questa risposta. –

+0

I puntatori non hanno un costruttore di copie. –

16

Assegnare cp il valore della memoria allocata. Tuttavia, questa è una variabile in pila: una copia di cp in main! cp è locale alla funzione si è in

quello che vuoi è un punto di riferimento:..

void func(char *& cp) 

Ciò alias cp ad essere il parametro passato in

1

si sta passando a cbuf , non cp.

+0

anche se passasse * cp, rimarrebbe puntato a 0 dopo // codice –

+1

Non importa, perché lo stai anche passando per valore. – mob

1

La funzione è solo cambiando una copia di cp. Usa invece un riferimento.

0

Come Gman e Neil menzionati, al fine di lavorare si dovrà cambiare func a:

char* func();

o void func(char*& p);

che risolverà il tuo problema immediato.

C'è, tuttavia, un problema di manutenzione. In entrambi i casi, func restituisce un puntatore. Ciò che non è chiaro all'utente di func è che il puntatore restituito dovrà essere cancellato. Per questo motivo, in generale, evita questo costrutto a meno che non sia necessario il 100%. Piuttosto:

  1. aiutare l'utente allocare la quantità corretta di memoria che possono poi essere passato a FUNC
  2. Utilizzare un oggetto per memorizzare la memoria allocata. L'oggetto può quindi cancellare l'array di caratteri quando viene distrutto.

Così, per il codice C++, mi raccomando:


class CBuf 
{ 
public 
    CBuf() 
    { 
     iBuf = new char[100]; 
    } 
    ~CBuf 
    { 
     delete[] iBuf; 
    } 
    char* func() 
    { 
     //do stuff; 
     return iBuf; 
    } 
private: 
    char* iBuf; 
}; 

int main() 
    { 
    CBuf cb; 
    char* mychar = cb.func(); 
    //do stuff with character array 

    //destructor gets called here because cb goes out of scope 
    } 

Tuttavia, nella programmazione C in particolare, potrebbe essere necessario al 100% per avere qualche funzione di ordinamento per creare l'array. Pertanto nella programmazione C è possibile sostituire il distruttore con una funzione CreateCBuf e DestroyCBuf. In questo modo l'utente della tua libreria saprà che il buffer restituito deve essere distrutto.

+0

Posso chiedere cosa c'è che non va con 'std :: vector'? – GManNickG

+0

std: vector va bene. Gestisce tutta la gestione della memoria per te. Il problema nell'esempio OPs è che la proprietà è molto poco chiara. – doron

1

Anche se i riferimenti sono meravigliosi nell'offrire un'astrazione intuitiva, rafforzata ulteriormente dal C++ 11 riferimenti rvalue per consentire la funzione concatenamento (e altri codici esoterici), si può affermare che essi forniscono alcuna sicurezza (cioè why is a reference considered safer than a pointer) Ci sono casi dove è meglio risolvere il precedente con un puntatore all'argomento della funzione del puntatore. In particolare quando è necessario mantenere un codebase simile in ansi c e C++.

#include <iostream> 

using namespace std; 

void func(char ** cp) { 
    *cp = new char[100]; 
    //do something useful 
    (*cp)[0] = 'A'; 
} 

void func(char *& cp) { 
    cp = new char[100]; 
    //do something useful 
    cp[0] = 'B'; 
} 

int main(int argc, char** argv) { 
    char * cp; 
    //pointer to pointer 
    func(&cp); 
    cout << "Index 0 : " << cp[0] << '\n' << flush; 
    delete[] cp; //remember to delete!! 
    //pointer to ref 
    func(cp); 
    cout << "Index 0: " << cp[0] << '\n' << flush; 
    delete[] cp; 
    return 0; 
} 

Ovviamente lo smaltimento delle risorse di memoria dall'ambito della funzione di instradamento disubbidisce a RAII.

Problemi correlati