2013-04-15 15 views
5

mam wskaźnik do wektora:jak stworzyć wektor wskaźników do wektora

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 
vector<double>* new_mv_pt = new vector<double> (3); 
new_mv_pt = &mv;  

cout << (*new_mv_pt)[1] << endl;  

Jak mogę dokonać innego wektora, który będzie przechowywać ten wskaźnik do wektora? Próbowałem tego ...

vector<double*> vop = new vector<double> (3); 

vop.push_back(*new_mv_pt); 

cout << (*vop)[1] << endl; 

ale to nie zadziałało. Czy to, co ja w ogóle możliwe próby ?:

+2

Po pierwsze, uzyskaj odpowiedź. Po drugie, zdaj sobie sprawę, że jest to okropny pomysł, ponieważ eliminujesz zdolność wektorem do zarządzania pamięcią, co jest (co najmniej) o połowę mniejsze niż użycie go w pierwszej kolejności. –

+0

Po prostu próbuję dowiedzieć się, dlaczego ma on wskaźnik do wektora w pierwszej kolejności. Nie ma sensu koncepcyjnego, aby robić to w ten sposób, szczególnie jeśli jest to ta sama funkcja/klasa. –

Odpowiedz

3

Tak, ale trzeba to zrobić:

vector<vector<double>*> vop; 

Ponieważ szukasz listy wskaźników wektorowych.

Co masz tutaj:

vector<double *> vop 

jest po prostu wektorem double wskaźników.

również będzie po prostu chcesz to:

vop.push_back(new_mv_pt); // <- No asterisk (you don't want to de-reference it) 
+0

Jak mam usunąć dwa wskaźniki, aby uniknąć wycieku pamięci? Próbuję usunąć new_mv_pt i pojawia się jakiś błąd asercji w czasie wykonywania. Jaki jest problem? –

+0

Co masz na myśli mówiąc o obu wskazówkach? masz na myśli 'new_mv_pt' i ten w wektorze? –

+0

Cóż, gdy próbuję usunąć new_mv_pt bez bycia w wektorze wskaźników, to nie zadziała i pojawi się jakiś błąd asercji w czasie wykonywania. Na koniec chciałbym wiedzieć, jak usunąć to wszystko bezpiecznie. –

2

masz wyciek pamięci tutaj:

vector<double>* new_mv_pt = new vector<double> (3); 
new_mv_pt = &mv; 

tworzysz vector<double> na stercie, przechowywania To adres w new_mv_pt, a następnie nadpisując ten adres z adresem mv. Model vector<double> nadal istnieje na stercie, ale utraciłeś na stałe jego adres (a zatem nie ma możliwości jego usunięcia lub wykonania jakiejkolwiek innej czynności).

ten kod:

vector<double*> vop = new vector<double> (3); 
vop.push_back(*new_mv_pt); 
cout << (*vop)[1] << endl; 

nie działa, ponieważ vop jest wektorem double* s, a próbujesz wstawić vector<double> do niego. Aby uzyskać prawidłowe podejście, patrz Ben's answer.

7

Whoa, zwolnij tam!

Robisz jakieś szalone rzeczy z pamięcią, więc zacznijmy od początku.

Masz jeden wektor, który zawiera 3 elementy. Chcesz odwołać się do tego wektora za pomocą wskaźnika. Zobaczmy, jak to wygląda:

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 
// No no no no! You don't have to `new` a pointer that 
// you're going to assign to something else! 
// This is called a memory leak, and it means you've just wasted (!!!) 
// C++ memory! Don't do it 
// vector<double>* new_mv_pt = new vector<double> (3); 
// Instead, do this: 
vector<double>* ptr_to_mv = &mv; // No leak, immediately points to a vector<double> mv; 

To dba o pierwszy bit. Teraz wejdźmy w to nieco głębiej. Chcesz przechowywać wektor odniesień do wektorów. W porządku, to brzmi uczciwie. Jest na to kilka sposobów.Wróćmy do przykładu mv i innych rzeczy:

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 
vector<double>* ptr_to_mv = &mv; 
// So far so good. Now, based on your question, you want 
// to have a list of these to point to. So: 
vector<vector<double>*> vop; 
vop.push_back(ptr_to_mv); // All clean. 

W tym momencie w kodzie, masz dostęp do vop z .at() lub operator[] dostać się do vector<double>*, wtedy dereference niego z * lub użytkowania -> pracować na nim bezpośrednio:

std::vector<double>* ptr_to_vector = vop[0]; // Got my pointer 
std::cout << ptr_to_vector->at(0) << std::endl; // Prints '233' 

drukuje 233, ponieważ wszystko to ty przedstawieniu mv. W komentarzu w innej odpowiedzi powiedziałeś, że gdy usuniesz te wskaźniki, otrzymasz potwierdzenie. To ma się stać, ponieważ dwa razy usuwasz rzeczy!

Pamiętasz mv, którą zadeklarowałeś dawno temu? Cóż, nie zrobiłeś tego dynamicznym wektorem. Nie zrobiłeś tego, a nie był to wskaźnik. Więc kiedy funkcja się zakończy, automatycznie usunie się - wywoła jej destruktor i zginie na stosie na stosie. Jeśli spojrzeć na ptr_to_vector lub ptr_to_mv, wszystkie odnoszą się do mv, które czyści się.

Jeśli wywołasz na nim usunięcie, próbujesz połączyć się z usunięciem pod numerem mv (to właśnie wskazujesz) i dwukrotnie usuwasz!

Tak więc, jeśli masz wskaźnik do mv, nie usuwaj go. Jest to zmienna oparta na stosie. Oczyści się.

Nadal śledzisz? Wielki, przejdźmy do niego nieco więcej:

Teraz, jeśli istnieje powodem trzeba new się wektor, nie przypisać go nadpisać starą wskaźnika (jak już mówiłem wcześniej, opuścisz pamięć). Zrobić zupełnie nowy, świeży wskaźnik:

// Our vector of double vector pointers 
vector<vector<double>*> vop; 

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 

// References a stack variable: don't delete 
vector<double>* ptr_to_mv = &mv; 
vop.push_back(ptr_to_mv); 

// Makes a fresh copy of mv. You must delete this 
// manually 
vector<double>* fresh_ptr = new vector<double>(mv); 
(*fresh_ptr)[0] = 1337; 
// changes only data in fresh_ptr, not `mv` 
vop.push_back(fresh_ptr); 

/* Blah blah blah, work */ 
// Functions about to exit, gotta clean up! 
delete fresh_ptr; 
//delete ptr_to_mv; // NO. 
//delete vop[0]; // NO! 
//delete vop[1]; // ... Already deleted from fresh_ptr 
// ... This is going to get tedious if we don't have a fresh_ptr 
// for every vector we need! 

Powyższe pokazuje problem: mamy 2 wskaźniki, zarówno wewnątrz vop, gdzie trzeba być czyszczone przez wywołanie usunąć, a inny, że nie, bo to jest po prostu odniesienie do mv, które czyści się automatycznie! Zapętlanie się wektora i usuwanie wszystkiego spowoduje, że stanie się to paskudne stwierdzenie. Jak sobie z tym poradzić i nadal mamy oczyszczenie, którego potrzebujemy?

Brudne i szybkie rozwiązanie 1 to tylko delete vop[1]/fresh_ptr i gotowe. Lepszym rozwiązaniem jest to, że gdy tylko podasz zasób, zamykasz go w tej wspaniałej rzeczy o nazwie std::unique_ptr. Kod będzie wyglądał tak:

// Our vector of double vector pointers. Non-owning 
vector<vector<double>*> vop; 

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 

// References a stack variable: don't delete 
vector<double>* ptr_to_mv = &mv; 
vop.push_back(ptr_to_mv); 

// Makes a fresh copy of mv 
// puts it inside a std::unique_ptr, 
// which, like a stack-based vector, 
// can clean itself up 
std::unique_ptr<vector<double>> fresh_ptr(new vector<double>(mv)); 
vop.push_back(fresh_ptr.get()); 

/* Blah blah blah, work */ 
// Functions about to exit, gotta clean up! 
//delete fresh_ptr; // Not necessary 
//delete ptr_to_mv; // Nope.jpg 

I proszę, usuń cały ten skomentowany kod i nagle twoje rzeczy są czyste jak gwizdek!

Oczywiście, teraz ostatnie pytanie mam dla was jest: Co do cholery robisz, że wymaga, aby wszystkie te wskaźniki do wskaźniki do odniesienia wskaźników wektorów?

+0

To było bardzo pomocne. Dużo mnie nauczyłeś. Dziękuję Ci bardzo. –

+0

To jest niezwykle szczegółowa odpowiedź na bardzo proste pytanie. Pan jest pro! +1 –

Powiązane problemy