2010-02-05 2 views
5

Ich habe eine Klasse namens Spring in einem Partikelsystem. Der Konstruktor wie folgt aussieht:Verweis auf Element in 2d Vektor (C++)

Spring(Particle& _a, Particle& _b); 

Und ich habe einen Vektor von Partikeln und ich verwende

Spring mySpring = Spring(myParticles.at(j),myParticles.at(j+1)); 

in einer Schleife um eine Federkraft zwischen zwei Teilchen hinzuzufügen. Bis jetzt funktioniert alles gut. Allerdings möchte ich einen 2d Vektor von Particles verwenden. Das ist:

Spring mySpring = Spring(myParticles.at(i).at(j),myParticles.at(i).at(j+1)); 

Und ich bekomme keinen Hinweis auf das Teilchen. Im ersten Beispiel ändert sich das Partikel im Vektor, wenn ich das Partikel in meiner Federklasse ändere. Im zweiten Beispiel sind die Änderungen nur lokal. Wie kann ich die Partikel im 2D-Vektor ändern?

EDIT: ich versuchen, einige Dinge klar zu machen:

ich einige Partikel-Systeme haben und jeder von ihnen besteht aus einer Anzahl von Partikeln. Jedes Teilchen sollte nur mit den anderen Teilchen interagieren, die sich in demselben System wie er selbst befinden. Deshalb habe ich einen Vektor von Teilchensystemen, wobei jedes Teilchensystem ein Vektor von Teilchenobjekten ist. (Das macht den 2d Vektor). Die erste Dimension (i) ist das System, die zweite (j) das einzelne Teilchen. Die Partikel im System interagieren miteinander (kollidieren, vermeiden, was auch immer ..) und ihre Positionen ändern sich. Und der Vektor wird "aktualisiert". (Das heißt, die Referenz funktioniert).

Allerdings habe ich einen zweiten (1d) Vektor der Federkräfte. Die Federkraft wird auch verwendet, um die Positionen der Partikel zu aktualisieren. Mein Konstruktor macht folgendes:

Spring::Spring(Particle& _a, Particle& _b) { 
    a=&_a; 
    b=&_b; } 

Mit a und b Particle * zu sein. Also speichere ich Zeiger auf zwei Partikel im 2D-Vektor. Eine weitere Funktion Spring.doSpring() ändert die Position der Partikel.

a->pos.x=300; 

oder

a->velocity+=something.. 

Im ersten Beispiel, das ich geschrieben habe ich nur ein Partikelsystem verwendet und so gab es keine Notwendigkeit für einen 2D-Vektor. Und alles funktioniert gut. Die Partikel im Vektor werden aktualisiert. Aber mit dem zweiten Beispiel läuft mein Programm, aber egal was die doSpring Funktion tut, die Partikel im 2d Vektor werden nicht aktualisiert.

+0

Wie erklärst du "myParticles"? – coelhudo

+0

Hey, ein Tipp von http://www.drdobbs.com/cpp/184401863: "Überschreibt die Namensgebung nicht, sondern verwendet eine konsistente Namenskonvention: Es gibt nur zwei Muss-Punkte: a) Niemals" hinterhältige Namen "verwenden "diejenigen, die mit einem Unterstrich beginnen oder einen doppelten Unterstrich enthalten"; Worte von Herb Sutter und Andrei Alexandrescu – coelhudo

Antwort

0

Wenn ich richtig verstehe, möchten Sie ein 2D-Array von Partikeln mit std::vector erstellen?

Wenn ja, können Sie es wie folgt deklarieren: std::vector<std::vector<Particle> >. Sie könnten dann sogar die [][] Nomenklatur verwenden, um auf Elemente zuzugreifen. (Gefahr wird Robinson! Keine Grenze Überprüfung während dieses Operator)

Allerdings, wenn dieser 2D-Array meist Nullen enthalten wird, dann könnte es in Ordnung, ein map mit Indizes als Schlüssel zu verwenden.

+0

Nach seinem Code ('.at (i) .at (j)') zu urteilen, verwendet er bereits einen Vektor von Vektoren. –

+0

Nach den obigen Beispielen zu urteilen, sieht dies genau so aus, wie er es bereits versucht hat (der "at (...). At (...)" -Teil). – rjnilsson

1

Ich denke this series von C++ FAQ Lite sollte helfen.

Bitte nicht durch den Header "Operator Overloading" verwechselt werden.Sie sollten unbedingt 13.10, 13.11 und 13.12 von dort lesen.

5

Was Sie tun, sieht nicht gut aus - der folgende Code erstellt ein „2D“ Vektor und zeigt, dass die .at() at() Konstrukt gibt Ihnen eine Referenz:

#include <vector> 
#include <iostream> 
using namespace std; 

int main() { 
    vector <vector<int> > vi; 
    vi.push_back(vector <int>()); 
    vi.at(0).push_back(42); 
    cout << vi.at(0).at(0) << endl; // prints 42 
    vi.at(0).at(0) = 666; 
    cout << vi.at(0).at(0) << endl; // prints 666 
} 
6

Einer der. häufige Probleme, die Referenzen/Zeiger auf Elemente innerhalb von Vektoren nehmen, sind Neuzuweisungen. Wenn Sie beispielsweise push_back verwenden, ist es möglich, dass der Vektor seine Kapazität überschreitet, einen neuen Speicherblock zuweist, alles kopiert und dann den alten Block freigibt. Wenn Sie Referenzen oder Zeiger auf Elemente innerhalb des Vektors genommen haben, zeigen diese immer noch auf den alten Block, jetzt toter Speicher, und ist ein ernsthafter Fehler!

Ich vermute also, dass Ihr Partikeleffekt neue Partikel zu Ihrem Partikelvektor hinzufügt, wodurch der Vektor irgendwann neu zugewiesen wird, wenn er die Kapazität überschreitet. Die Zeiger, die von der Spring-Klasse gespeichert werden, werden jedoch nicht aktualisiert, weisen also auf toten Speicher und haben keine Auswirkungen auf das tatsächliche Partikel, das durch den Vektor an anderer Stelle verschoben wurde.

Nimm keinen Verweis oder Zeiger auf ein Element in einem Vektor. Verwenden Sie einen Zeigervektor, eine Liste oder einen anderen Container, der die Speicheradressen tatsächlicher Elemente nicht umsorgt. Wenn Sie müssen, verwenden Sie Iteratoren zu Elementen innerhalb eines Vektors. Wenn Sie in debug-Builds eine überprüfte STL-Implementierung verwenden, erhalten Sie eine Debug-Warnung, wenn Sie über den Iterator auf das Element zugreifen, nachdem der Vektor sich neu zugeordnet hat.

+1

Aber würde das nicht Null Zeiger verursachen, die die Anwendung zum Absturz bringen würde? Da meine Anwendung nicht abstürzt, werden die Elemente nicht aktualisiert. Aber das ist eine gute Antwort, ich habe nicht über die Neuzuweisung nachgedacht. – hrst

+0

Nein, nichts wird auf einen Null-Zeiger gesetzt: Vektor weiß nichts über die Zeiger in der Spring-Klasse, macht also keinen Versuch, sie zu ändern. Die Zeiger * sind nicht * modifiziert oder Null, sie zeigen nur auf einen toten Speicherplatz. Da sich der Speicher wahrscheinlich irgendwo in Ihrem Prozess befindet, sind Lese- und Schreibvorgänge zulässig, obwohl Sie wahrscheinlich den Speicher Ihrer Anwendung beschädigen. – AshleysBrain