2015-04-22 15 views
7

Widzę inne pytania, które wyglądają jak moje, ale nadal nie mogę tego zrozumieć.Dlaczego obiekty utworzone w pętli mają ten sam adres?

Oto mój kod:

#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"; 
    } 
} 

Gdy ten, „nowy adres węzła A” jest zawsze taki sam adres, ale powtarza się każdej iteracji „Adres nowy węzeł B” jest inny adres każdym razem.

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 

Nie rozumiem, dlaczego aib nie są tym samym. Dokładniej: czy nie jest & newNode adres obiektu, który właśnie utworzyłem? I czy vectorOfNodes [i] także nie jest tym obiektem? Więc nie jest to wektor2fc [2] również adres obiektu?

+5

Kompilator magiczny. –

+0

aib nie są takie same, ponieważ są to różne obiekty w różnych lokalizacjach pamięci. a jest prawdopodobnie taka sama dla każdej iteracji, ponieważ ten adres pamięci może być ponownie użyty dla każdej iteracji jako miara optymalizacji. – twsaef

+0

Czy & noNode nie jest adres obiektu, który właśnie utworzyłem? I czy vectorOfNodes [i] także nie jest tym obiektem? Więc nie jest i vectorOfNodes [i] także adres obiektu? –

Odpowiedz

9

Te informacje są wyjaśniane na każdym kursie na poziomie uczelni dotyczącym projektowania systemu operacyjnego i/lub projektowania kompilatora.

Obiekty, o których mowa, są tworzone na stosie, a na końcu zakresu wykraczają poza zakres na stosie. Stos narasta i kurczy się odpowiednio, a ponieważ w każdej iteracji pętli tworzone są te same dokładne obiekty (i niszczone), stos rośnie i kurczy się o tę samą wartość, więc te same obiekty zawsze kończą się uzyskiwaniem wystąpienia w tej samej lokalizacji na stosie.

W praktyce kompilator może wykonać pewne optymalizacje i obliczyć dużą ilość stosu, z którego będzie korzystała każda funkcja, przez większość czasu, a tym samym "przerośnie" stos do dużej ilości funkcji, której będzie potrzebować; ale że będzie trochę zbyt daleko do chwastów ...

To jest tak zwięzły odpowiedź jak mogę dać, bez wchodzenia całego wykładu co stos jest, etc ...

Teraz inny obiekt jest przydzielany na stercie. Skoncentruj swoją uwagę na tym, że na końcu pętli obiekt, który wepchnąłeś do wektora, istnieje, podczas gdy obiekt "a" zostaje zniszczony, a zaczniesz dostrzegać różnicę. Przy każdej iteracji pętli tworzony jest obiekt "a", a następnie niszczony na końcu pętli (i ponownie tworzony na początku pętli), podczas gdy obiekt włożony do wektora nadal istnieje.

+0

To było bardzo jasne i pomocne. Czy najpierw należy umieścić obiekt na stosie, a następnie skopiować go do sterty? Czy mógłbym jakoś pominąć pierwszy krok? –

+2

Pewnie. Mogłeś po prostu napisać: vectorOfNodes.push_back (node ​​ (i, NULL)); W rzeczywistości, jeśli pozbędziesz się zrzutów do std :: cout i skompilujesz swój kod na wystarczająco wysokim poziomie optymalizacji, kompilator prawdopodobnie zoptymalizuje kod w ten sposób automatycznie (w zależności od tego, co kompilator może dowiedzieć się o klasie skopiować konstruktorów). –

0

Operacja push_back kopiuje newNode do wektora. Dlatego każda kopia jest pod innym adresem.

-2

Tutaj;

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

Nie tworzysz nowego węzła, tylko przypisujesz mu nową wartość.

Nowe wektory są tworzone wewnątrz wektora przy użyciu domyślnego konstruktora kopiowania. Jeśli chcesz, aby twój wektor zawierał węzły, które do niego wstawiasz, powinieneś użyć wskaźnika takiego jak ten;

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

To jest deklaracja. Tworzy nowy obiekt typu 'node ' i inicjuje go. – EJP

+0

@EJP Ta inicjalizacja jest konstrukcją kopii. – douyw

+1

@douyw To "inicjowanie kopiowania", kompilator może wykonywać kopiowanie, ale konstruktor kopii musi być dostępny. – BenPope

Powiązane problemy