2016-06-17 10 views
6

Grazie per aver controllato la mia domanda. Ho appena riscontrato un problema davvero fondamentale quando sto implementando un BST, ovvero "qual è la differenza nei diversi approcci per assegnare un puntatore?" Sappiamo tutti che assegna un punto può utilizzare:Qual è la differenza tra le modalità di assegnazione di un puntatore?

int *p, q; 
p = &q; 

Oppure:

int *p, *q; 
p = q; 

Dovrebbero essere gli stessi. Ma nel mio caso al di sotto, si lavora totalmente differente:

template <typename T> 
void Tree<T>::_insert(TreeNode<T>*& tree, const T& value, const unsigned& key) 
{ 
// TreeNode<T> node(value, key); 
// if(tree == nullptr) tree = &node; 
    TreeNode<T> *node = new TreeNode<T>(value, key); 
    if(tree == nullptr) tree = node; 

    else if(key < tree->index) _insert(tree->left, value, key); 
    else if(key > tree->index) _insert(tree->right, value, key); 
    else if(key == tree->index) std::cerr << "_insert: repeating key" << std::endl; 
} 

Utilizzando il primo modo (rilevato uno), la funzione non assegnerà albero uguale a node, mentre il secondo modo funziona bene.

Quindi, questa è colpa mia, o sono naturalmente diversi?

risposta

3

Si prega di notare, nel primo caso:

// TreeNode<T> node(value, key); 
// if(tree == nullptr) tree = &node; 

node è un oggetto allocato sul pila.

Mentre nel secondo caso

TreeNode<T> *node = new TreeNode<T>(value, key); 
if(tree == nullptr) tree = node; 

node viene allocato su mucchio.

La differenza è che una volta restituita la funzione _insert, il suo stack frame viene popolato e tutte le variabili/oggetti locali non sono più validi, di conseguenza, si avranno errori di memoria.

+0

Grazie per la vostra risposta, lo apprezzo molto. Quindi, se ho capito bene, il motivo per cui ho ottenuto un errore è perché la variabile dichiarata nell'heap verrà liberata quando supera l'ambito, quindi, nel primo caso, il "nodo" verrà liberato e il puntatore "albero" verrà reimpostato in "nullptr", giusto? –

+0

@XiangyuZhang No, la memoria allocata nell'heap non verrà liberata a meno che non lo facciate esplicitamente (ecco perché non avete avuto problemi nel secondo caso). Per il primo caso, il puntatore "tree" non verrà reimpostato su "nullptr" una volta che il frame stack di _insert è spuntato, rimarrà comunque quello che era, ma poiché _insert() è tornato, quale "albero" punta a è solo una memoria casuale (lo stack frame delle seguenti chiamate di funzioni sovrascrive la memoria dello stack allocata), il dereferenziamento/accesso al puntatore "tree" è certamente problematico. –

+0

@XiangyuZhang Forse è utile guardare https://en.wikipedia.org/wiki/Call_stack#STACK-FRAME –

3

n, le due vie non dovrebbe essere lo stesso:

  • La prima assegnazione p = &q è perfettamente valido, perché q è l'oggetto reale in memoria, e p è un puntatore ad esso
  • La seconda assegnazione p = q assegna un puntatore unitario q a p, che è un comportamento non definito.

Ecco perché le due implementazioni sono diverse.

Se si desidera assegnare q a p, è necessario assegnare prima lo q stesso. Ad esempio, è possibile assegnare ad esso new int:

int *p, *q = new int; 
p = q; 

Tuttavia, in questo caso si potrebbe anche assegnare new int direttamente a p.

0
int *p, q; 
p = &q; 

Ciò significa che p ora ha l'indirizzo in cui è memorizzato il numero intero q.

int *p, *q; 
p = q; 

In questo si sta copiando l'indirizzo memorizzato nel puntatore da q a p.

Problemi correlati