2009-12-11 18 views
7

Ho un incarico che richiede l'implementazione di una classe di elenchi doppiamente collegata. Per qualche motivo hanno definito il nodo struct come segue:Doppi elenchi collegati in C++

struct node { 
    node *next; 
    node *prev; 
    T  *o; 
}; 

Mi sembra che sarebbe stato molto più facile di scrivere la classe se la 'data' membro struct non fosse un puntatore. Inutile dire che non posso cambiarlo, quindi dovrò solo aggirarlo. Ho provato l'attuazione del metodo che aggiunge un elemento all'inizio della lista come segue:

template <typename T> 
void Dlist<T>::insertFront(T *o) { 
    node *np = new node; 
    T val = *o; 

    np->o = &val; 
    np->prev = NULL; 
    np->next = first; 

    if (!isEmpty()) { 
     first->prev = np; 
    } else { 
     last = np; 
    } 
    first = np; 
} 

durante l'utilizzo di ddd per eseguire il debug ho capito che tutto funziona bene la prima volta che si inserisce un numero, ma la seconda volta tutto diventa avvitato poiché non appena si imposta 'val' sul nuovo elemento esso "sovrascrive" il primo poiché è stato utilizzato l'indirizzo di memoria di val. Ho provato a fare altre cose come invece di avere la variabile 'val' facendo quanto segue:

T *valp = new T; 
T val; 
valp = &val; 
val = *o; 

np->o = valp 

Anche questo non sembra funzionare. Penso che sia perché è solo una forma più complicata di ciò che ho fatto sopra solo con una perdita di memoria aggiuntiva :)

Qualsiasi idea/puntatore nella giusta direzione sarebbe ottima.

+4

+1 per il disclaimer compiti onorevole. –

+0

Dai uno sguardo a questo, la prima risposta può aiutarti a capire il problema: http://stackoverflow.com/questions/5727/what-are-the-barriers-to-understanding-pointers-and-what-can-be -dato-a-superare – Dan

+0

Quando hai la possibilità di dare un'occhiata anche a questo: http://stackoverflow.com/questions/599308/proper-stack-and-heap-usage-in-c - differenza tra stack e allocazione dell'heap. – Dan

risposta

6

il T val creato è una variabile automatica. Il tuo errore sta memorizzando l'indirizzo in quella variabile stack.

Si dovrebbe utilizzare new per allocare spazio nell'heap, come si sospetta, ma il puntatore dei dati deve puntare direttamente all'indirizzo restituito da new.

Il tuo errore nel suo ultimo tentativo è qui:

valp = &val; 

State cambiando valp a punto da qualche altra parte (l'indirizzo della val), quando si sta probabilmente tentando di dati copia di val, non il suo indirizzo.

I dati trasmessi alla funzione devono essere copiati nella nuova memoria in cui punti valp.

+0

Ahh. Questo ha un senso sul motivo per cui stavo riportando i valori -1074723840 quando stavo cercando di leggere i valori. Questo aiuta anche se immagino di non essere ancora abbastanza sicuro su come risolvere il problema? Puoi darmi qualche parola chiave che potrebbe aiutarmi nella mia ricerca? Grazie. – blcArmadillo

+1

Solo pignoli: val non è un temporaneo. È una variabile "automatica", ovvero una variabile stack. Altrimenti, buona risposta. – Dan

+0

http://en.wikipedia.org/wiki/Automatic_variable – Dan

0
T val = *o; 

    np->o = &val; 

Questa parte è sospetta. Il suggerimento è che la memoria allocata sullo stack in una funzione non sarà disponibile una volta che la funzione non rientra nello scope.

4

Non credo che si dovrebbe fare questo:

T val = *o; 

Dal momento che il membro o nella struttura nodo è un puntatore, e il parametro da insertFront è anche un puntatore, il vostro istruttore probabilmente intende per voi prendere il puntatore che ti è stato dato e memorizzarlo nell'elenco, non creare una copia dell'oggetto e memorizzare un puntatore. È sufficiente memorizzare il puntatore o passato in insertFront come membro del nodo o e si dovrebbe essere OK.

+1

sono assolutamente d'accordo. Dovrebbe piuttosto essere 'np-> data = o;' –

+0

Non necessariamente. Ci dovrebbero essere alcuni commenti che spiegano se il T * passato è assegnato o meno dinamicamente e se il DList dovrebbe assumerne la proprietà o se si suppone che faccia una copia. Se non conosci le risposte a queste domande, non puoi implementarlo correttamente se non per fortuna. – Dan

+1

@Sammy, come fai a sapere che non dovrebbe essere 'np-> data = new (* o);'? – Dan

0

Il codice non si adatta la tua definizione di node - in node si sta definendo un membro data, ma nel codice che si sta utilizzando, invece o.

In ogni caso, è necessario eseguire due allocazioni dinamiche per aggiungere ciascun nodo, uno per il nodo stesso e uno per l'oggetto dati a cui verrà indirizzato. Quando si assegna l'oggetto dati, è possibile assegnare il valore restituito da new direttamente al puntatore nel nodo. Quindi dovrai copiare l'oggetto dati il ​​cui puntatore è stato passato nell'oggetto dati appena assegnato, a cui punta il puntatore nel nodo.

+0

Buona presa. Ho modificato la struttura dopo averla copiata in SO e ho dimenticato di cambiarla in altri posti. – blcArmadillo

0

Si si pensa il carico utile del puntatore è inopportuno. Ma forse l'elenco è destinato a essere utilizzato per creare un collegamento in cima oggetti esistenti, come in:

struct A { int i; }; 
A as[10] = { 1,2,3,4,5,6,7,8,9,10 }; 

LinkedList primes_in_my_data; 
insertFront(primes_in_my_data, &as[1]); 
insertFront(primes_in_my_data, &as[2]); 
insertFront(primes_in_my_data, &as[3]); 
insertFront(primes_in_my_data, &as[5]); 
insertFront(primes_in_my_data, &as[7]); 

// now I have a linked list of primes, and caused no extra memory allocation 
// (except for the list overhead) 
Problemi correlati