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?
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. –
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. –