2015-04-22 11 views
7

Vedo altre domande simili al mio, ma non riesco ancora a capirlo.Perché gli oggetti creati in un loop hanno lo stesso indirizzo?

Ecco il mio codice:

#include<iostream> 
#include <vector> 

using namespace std; 

template<typename Data_Type> 
    class node { 
     public: 
     Data_Type data; 
     node* next; 
     node(Data_Type data, node* next){ 
      this->data = data; 
      this->next = next; 
     } 
    }; 


int main(){ 
    vector<node<int> > vectorOfNodes; 
    for (int i = 0; i< 4; i++){ 
     node<int> newNode = node<int>(i,NULL); 
     std::cout << "new node address a "<< &newNode << "\n"; 
     vectorOfNodes.push_back(newNode); 
     std::cout << "new node address b "<< &vectorOfNodes[i] << "\n"; 
    } 
    for (int i = 0; i< 4; i++){ 
     std::cout << "data "<< vectorOfNodes[i].data << "\n"; 
    } 
} 

Quando eseguo questo "nuovo indirizzo di nodo a" è sempre lo stesso indirizzo ripete ogni iterazione, ma "l'indirizzo nuovo nodo b" è un indirizzo diverso ogni volta.

new node address a 0x7fff546c39b0 
new node address b 0x7fe2f8c039d0 
new node address a 0x7fff546c39b0 
new node address b 0x7fe2f8c039f0 
new node address a 0x7fff546c39b0 
new node address b 0x7fe2f8c03a20 
new node address a 0x7fff546c39b0 
new node address b 0x7fe2f8c03a30 
data 0 
data 1 
data 2 
data 3 

Non capisco perché aeb non sono uguali. Più precisamente: non è & newNode l'indirizzo dell'oggetto che ho appena creato? E non è vectorOfNodes [i] anche quell'oggetto? Quindi non è & vectorOfNodes [i] anche l'indirizzo dell'oggetto?

+5

Compilatore magico. –

+0

aeb non sono uguali perché sono oggetti diversi in diverse posizioni di memoria. a è probabilmente la stessa ogni iterazione perché quell'indirizzo di memoria può essere riutilizzato per ogni iterazione come misura di ottimizzazione. – twsaef

+0

Non è & newNode l'indirizzo dell'oggetto che ho appena creato? E non è vectorOfNodes [i] anche quell'oggetto? Quindi non è vectorOfNodes [i] anche l'indirizzo dell'oggetto? –

risposta

9

Questa roba è spiegata in ogni corso di livello universitario sulla progettazione del sistema operativo e/o sulla progettazione del compilatore.

Gli oggetti in questione vengono istanziati nello stack e, alla fine dello scope, escono dall'ambito dello stack. Lo stack cresce e si riduce di conseguenza, e poiché in ogni iterazione del ciclo, gli stessi oggetti esatti vengono creati (e distrutti), lo stack cresce e si restringe della stessa quantità, quindi gli stessi oggetti finiscono sempre per essere istanziati nella stessa posizione in pila.

In pratica, il compilatore può fare alcune ottimizzazioni e capire la grande quantità di stack che ogni funzione utilizzerà, il più delle volte, e quindi "pregrow" lo stack per la grande quantità di cui avrà bisogno la funzione; ma che sta andando un po 'troppo lontano nel erbacce ...

Questa è la risposta più conciso che posso dare, senza entrare in un intero lezione di ciò che una pila è, ecc ...

Ora, il l'altro oggetto è allocato sull'heap. Focalizza la tua attenzione sul fatto che, alla fine del ciclo, l'oggetto che hai inserito nel vettore è ancora, mentre l'oggetto "a" viene distrutto e inizierai a vedere la differenza. In ogni iterazione del ciclo viene creato l'oggetto "a", quindi distrutto alla fine del ciclo (e creato di nuovo all'inizio del ciclo), mentre l'oggetto inserito nel vettore esiste ancora.

+0

Ciò è stato molto chiaro e utile. È necessario prima mettere l'oggetto nello stack e poi copiarlo nell'heap? Potrei aver saltato il primo passo in qualche modo? –

+2

Sicuro. Potresti aver semplicemente scritto: vectorOfNodes.push_back (nodo (i, NULL)); Infatti, se ti sbarazzi dei dump su std :: cout e compili il tuo codice con un livello di ottimizzazione abbastanza alto, il compilatore probabilmente ottimizzerà il codice automaticamente in questo modo (a seconda di cosa il compilatore può capire riguardo alla tua classe copia i costruttori). –

0

L'operazione push_back copia newNode nel vettore. Pertanto ogni copia è a un indirizzo diverso.

-2

Qui;

node<int> newNode = node<int>(i,NULL); 

Non si sta creando un nuovo nodo, ma si assegna un nuovo valore ad esso.

Nuovi nodi vengono creati all'interno del vettore utilizzando il costruttore di copie predefinito. Se vuoi che il tuo vettore contenga i nodi che stai spingendo dentro, dovresti usare un puntatore, come questo;

vector<node<int>*> vectorOfNodes; 
+1

Questa è una dichiarazione dichiarazione. Crea un nuovo oggetto di tipo 'nodo ' e lo inizializza. – EJP

+0

@EJP L'inizializzazione è una copia. – douyw

+1

@douyw È "inizializzazione della copia", al compilatore è consentito eseguire elision di copia, ma il costruttore della copia deve essere accessibile. – BenPope

Problemi correlati