2013-04-15 17 views
5

Ich habe einen Zeiger auf einen Vektor:wie ein Vektor von Zeigern auf einen Vektor erstellen

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;  

Wie kann ich einen anderen Vektor zu machen, die diesen Zeiger auf einen Vektor gespeichert werden? Ich habe versucht, diese ...

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

vop.push_back(*new_mv_pt); 

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

aber es hat nicht funktioniert. Ist das, was ich versuche auch möglich ?:

+2

Zuerst erhalten Sie Ihre Antwort. Zweitens, erkenne, dass dies eine schreckliche Idee ist, weil du die Fähigkeit des Vektors eliminierst, das Gedächtnis für dich zu verwalten, was (zumindest) der halbe Punkt ist, es überhaupt zu benutzen. –

+0

Ich versuche nur herauszufinden, warum er überhaupt einen Zeiger auf einen Vektor hat. Es macht keinen konzeptionellen Sinn, es so zu tun, besonders wenn es in derselben Funktion/Klasse ist. –

Antwort

3

Ja, aber Sie müssen dies tun:

vector<vector<double>*> vop; 

Da Sie für eine Liste der Vektor Zeiger suchen.

Was haben Sie hier:

vector<double *> vop 

ist nur ein Vektor von double Zeiger.

Auch Sie werden nur diese wollen:

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

Wie würde ich beide Zeiger löschen, um ein Leck im Speicher zu vermeiden? Ich versuche, new_mv_pt zu löschen, und ich bekomme eine Art Assertionsfehler zur Laufzeit. Was ist das Problem? –

+0

Was meinst du beide Zeiger? meinst du 'new_mv_pt' und die im Vektor? –

+0

Nun, wenn ich new_mv_pt versuchen zu löschen, ohne in dem Vektor von Zeigern sind, wird es nicht funktionieren und kommt zur Laufzeit mit irgendeiner Art von Behauptung Fehlern auf. Am Ende möchte ich wissen, wie man alles sicher löschen kann. –

2

Sie haben ein Speicherleck hier:

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

Sie eine vector<double> auf dem Heap Erstellen, Speichern, es ist Adresse in new_mv_pt, und dann überschreiben diese Adresse mit der Adresse mv. Die vector<double> existiert immer noch auf dem Heap, aber Sie haben ihre Adresse dauerhaft verloren (und haben daher keine Möglichkeit, sie zu delete oder irgendetwas anderes damit zu tun).

Dieser Code:

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

funktioniert nicht, da vop ist ein Vektor von double* s, und Sie versuchen, eine vector<double> in sie einzufügen. Siehe Ben's answer für den korrekten Ansatz.

7

Whoa, langsamer dort!

Sie machen einige ziemlich verrückte Dinge mit Ihrem Gedächtnis, also fangen wir von vorne an.

Sie haben einen einzelnen Vektor, der drei Elemente enthält. Sie möchten diesen Vektor mit einem Zeiger referenzieren. Mal sehen, wie das aussieht:

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; 

Das kümmert sich um das erste Bit. Nun, lasst uns etwas tiefer hineingehen. Sie möchten einen Vektor von Referenzen auf Vektoren speichern. Okay, das klingt fair. Es gibt ein paar Möglichkeiten.Gehen wir zurück auf das Beispiel von mv und andere Dinge:

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. 

An dieser Stelle im Code, haben Sie vop mit .at() oder operator[] auf den Zugang zu einem vector<double>* zu bekommen, dann Sie dereferenzieren mit * oder Verwendung -> direkt daran arbeiten:

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

diese 233 druckt, weil alle diese Sie mv Referenzierung wird. In einem Kommentar in einer anderen Antwort sagten Sie, dass Sie eine Assertion erhalten, wenn Sie diese Zeiger löschen. Das soll passieren, weil du Dinge zweimal löschst!

Denken Sie daran, mv, dass Sie vor langer Zeit deklariert? Nun, du hast es nicht zu einem dynamischen Vektor gemacht. Du hast es nicht new it, und es ist kein Zeiger. Wenn die Funktion beendet wird, wird sie automatisch gelöscht - sie ruft ihren Destruktor und Chip auf dem Stapel. Wenn Sie sich ptr_to_vector oder ptr_to_mv ansehen, beziehen sich alle auf mv, die sich selbst reinigt.

Wenn Sie delete aufrufen, versuchen Sie, delete auf mv (das ist, was Sie zeigen) aufrufen und Sie sind doppelt löschen!

Also, wenn Sie einen Zeiger auf mv haben, löschen Sie es nicht. Es ist eine stack-basierte Variable. Es wird sich selbst reinigen.

Noch folgen? Große, lassen Sie uns in sie ein bisschen mehr bekommen:

Nun, wenn es ein Grund Sie einen Vektor new up benötigen, können Sie nicht zuordnen es mit einem alten Zeiger außer Kraft setzen (wie ich schon sagte, du wirst Speicher hinterlassen). Sie machen einen völlig neuen, frischen Zeiger:

// 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! 

Die oben zeigt das Problem: Wir haben zwei Zeiger, sowohl innerhalb als vop, wo man löschen, indem Aufruf gereinigt werden muss, und ein anderes, das nicht den Fall ist, weil es nur ein Verweis auf mv, die automatisch reinigt! Wenn Sie über den Vektor streichen und alles löschen, wird diese böse Behauptung ausgelöst. Wie gehen wir damit um und bekommen trotzdem das Saubermachen, das wir brauchen?

Dirty und Quick Solution 1 ist nur delete vop[1]/fresh_ptr und damit fertig sein. Die bessere Lösung ist, dass, wenn Sie eine Ressource auf new up, Sie es in diesem wunderbaren Ding namens std::unique_ptr einpacken. Der Code wird wie folgt aussehen:

// 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 

Und los geht, entfernen Sie alle, dass kommentierte-out-Code und plötzlich, Ihr Material ist picobello sauber!

Natürlich, jetzt die letzte Frage habe ich für Sie ist: Was zum Teufel machst du das verlangt, dass alle diese Zeiger auf Zeiger auf Referenzen von Zeigern von Vektoren?

+0

Das war sehr hilfreich. Du hast mir viel beigebracht. Vielen Dank. –

+0

Dies ist eine unglaublich detaillierte Antwort auf eine sehr einfache Frage. Sie sind ein Profi! +1 –