Bestimmter Wert schon im vector enthalten?
-
Der Funktor stand vorhin noch nicht da

Ja, das sollte gehen.EDIT: Siehe CStoll.
-
Ich weisz, sry, hab den gleich danach hinzugefügt. Aber hier antworten die Leute einfach zu schnell, hehe.
Achja, find_if() war's, sry. Hatte ich mal wieder vergessen.
-
Erstmal danke für Eure zahlreichen Antworten.
Habe es so probiert:
if (find_if(rPoints.begin(), rPoints.end(), ComparePoint(pPoint)) == rPoints.end()) { //create new point }und
class ComparePoint { public: bool operator () (const Point *& crLhs, const Point *& crRhs) { return (*crLhs) == (*crRhs); } };Ich bekomme jetzt beim Compilieren folgenden Fehler: "'<function-style-cast>': 'Point *' kann nicht in 'ComparePoint' konvertiert werden".
Gruß
Patrick
-
Ja, Funktoren sind kompliziert
find_if() erwartet eine Funktion/Funktor, die mit einem Parameter aufgerufen werden kann und einen bool zurückgibt - den Vergleich mußt du in deinem op() erledigen:struct ComparePoints : public unary_function<Point*,bool> { //Ctor - legt Vergleichwert fest ComparePoints(Point* tgt) : m_tgt(tgt) {} //op() - vergleicht übergebenen Wert mit Vergleichswert bool operator() (Point* akt) { return *akt == *m_tgt; } private: Point* m_tgt; }; ... if (find_if(rPoints.begin(), rPoints.end(), CompairPoint(pPoint)) == rPoints.end()) { //create new point }(PS: Zeiger sind klein genug, um sie per Value übergeben zu können - da ist die Übergabe als const-Referenz überflüssig ;))
-
Danke funktioniert super. Eine Sache noch. Könnt Ihr Euch folgenden Code mal bitte ansehen und mir schreiben, ob Optimierungen möglich sind (ganz bestimmt sind welche möglich). Außerdem habe ich die Vermutung, dass ich da ein Speicherloch programmiert habe. In Kommentaren gibt es noch eine zweite Variante, die funktioniert aber nicht, da man Iteratoren nicht dereferenzieren kann.
// Create new point. Point * pPoint = new Point(x, y, z); // If the point does not exist already then create a new one. //vector<Point *>::iterator iter = find_if(rPoints.begin(), rPoints.end(), ComparePoint(pPoint)); // version 2 //if (iter == rPoints.end()) // version 2 if (find_if(rPoints.begin(), rPoints.end(), ComparePoint(pPoint)) == rPoints.end()) // version 1 { cout << " not found!!!" << endl; // Point does not exist already. pPoint->SetIndex(rPoints.size()); rPoints.push_back(pPoint); } else { // Delete pPoint because of memory leak??? But it is needed below again!!! cout << " found." << endl; } // Memorize point index for neighborhoods. //int index = (*iter)->GetIndex(); // version 2 int index = (*find_if(rPoints.begin(), rPoints.end(), ComparePoint(pPoint)))->GetIndex(); // version 1Gruß
Patrick
-
Die beste Optimierung: Verwende keine Zeiger, wenn es nicht nötig ist (d.h. wenn keine echten Gründe dagegen sprechen, solltest du du einen vector<Point> verwenden - dann erübrigt sich auch die Speicherveraltung und das Gebastel mit dem Functor).
Ansonsten: Ja, im else-Zweig solltest du das per new angelegte Objekt wieder freigeben. Und die Suche solltest du nur einmal durchführen und dir das Ergebnis dann merken (die Lösung "version 2" solltest du auf jeden Fall verwenden - im else-Zweig noch ergänzt um ein
iter = rPoints.end()-1;).
-
Variante 2 würde ich ja gerne verwenden, aber Iteratoren können nicht dereferenziert werden.
Ohne Pointer geht es glaube ich nicht. Mal ein Wenig mehr zum Hintergrund: Ich schreibe mir ein Programm, welches aus einer Datei Flächen einliest. Jede Fläche besteht aus Drahtgittern, diese wiederum aus Kanten und die sind dann durch ihre Anfangs- und Endpunkte beschrieben. Beim Einlesen muss ich mir eine Topologie aufbauen, so dass ich hinterher weiß welche Punkte benachbart sind, welche Punkte zu welchem Drahtgitter gehören und welche Punkte zu einer Fläche gehören. Nachdem ich die Daten eingelesen habe, will ich die Punkte so sortieren, dass die Punkte, die den Rand der Fläche beschreiben in einer bestimmten Reihenfolge sind. Nun hatte ich mir folgendes überlegt:
Klasse Face:
- hat einen vector mit allen Punkten => vector<Point *>
- hat einen vector mit allen Drahtgittern => vector<Wire *>Klasse Wire:
- hat einen vector mit den sortierten Indizes der zugehörigen Punkte => vector<int>Klasse Point:
- Koordinaten => double x, double y und double z
- Pointer auf Nachbarn (jeweils zwei) => Point * pN0 und Point * pN1Beim Einlesen erstelle ich für jede Fläche eine Instanz der Klasse Face, in dieser wird die Methode processFace() aufgerufen. processFace() erstellt für jedes Drahtgitter der Fläche eine Instanz der Klasse Wire, in der dann wiederum processWire() aufgerufen wird. processWire() ruft für jede Kante des Drahtgitters processEdge() auf. processEdge() ist der Kern, hier werden die Instanzen der Point Klasse erstellt, wobei nur ein neuer Punkt erstellt werden soll, wenn nicht schon ein Punkt mit den selben Koordinaten existiert.
Kann man, dass ohne Pointer umsetzen?
Gruß
Patrick
-
Ja, kann man ohne Pointer umsetzen. Solange du ohne Polymorphie auskommst. Und das scheint bei deiner Point und Wire Klasse der Fall zu sein. Probier es doch einfach mal ohne Pointer! (du bist in der C++-Welt!) Der Code wird dadurch sogar kürzer.
-
PACoSys schrieb:
Variante 2 würde ich ja gerne verwenden, aber Iteratoren können nicht dereferenziert werden.
Wer erzählt denn sowas? Klar können Iteratoren dereferenziert werden, andernfalls wären sie ziemlich nutzlos.
-
CStoll schrieb:
Wer erzählt denn sowas?
Die Microsoft Visual C++ Debug Library. Ich kann das Projekt compilieren und ausführen, aber an dem Punkt wo ich den Iterator dereferenziere bekomme ich eine schicke Fehlermeldung:
Debug Assertion Failed!
Program: ...
File: ...
Line: ...Expression: vector iterator not dereferencable
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.@Artchi: Wo speichere ich dann meine Punkte, ich dachte die müsste ich mir mit Pointern merken?! Insbesondere die Nachbarschaft, bisher speichere ich mir einen Pointer, aber aus einem vector<Point> bekomme ich keinen Pointer.
Gruß
Patrick
-
PACoSys schrieb:
CStoll schrieb:
Wer erzählt denn sowas?
Die Microsoft Visual C++ Debug Library. Ich kann das Projekt compilieren und ausführen, aber an dem Punkt wo ich den Iterator dereferenziere bekomme ich eine schicke Fehlermeldung:
Debug Assertion Failed!
Program: ...
File: ...
Line: ...Expression: vector iterator not dereferencable
Da hast du vermutlich den falschen Iterator erwischt (sog. singuläre Iteratoren wie end() dürfen nicht dereferenziert werden, aber das mußt du abfangen, bevor du darauf zugreifen willst)
@Artchi: Wo speichere ich dann meine Punkte, ich dachte die müsste ich mir mit Pointern merken?! Insbesondere die Nachbarschaft, bisher speichere ich mir einen Pointer, aber aus einem vector<Point> bekomme ich keinen Pointer.
Warum speicherst du nicht die Indizes der Nachbarn im vector<> (und einen Verweis auf das Vater-Element)?
-
Zu der Assertion: dann wird der Iterator wohl ungültig sein, sprich Null. Es ist ein Laufzeitfehler und kein Compile-Fehler, oder? Also lässt sich der Iterator prinzipiell dereferenzieren, aber zur Laufzeit schein ein ungültiger Wert drin zu stecken. Wahrscheinlich wird es der end-Iterator sein? Und den sollte man auch nicht dereferenzieren, da er HINTER das letzte Element im Container zeigt.
Zu den vector<Point>: die Points werden als Objekte gespeichert, und nicht als Pointer.
Hier mal ein paar Basics:
http://www.kharchi.de/cppratgeber1.htm
http://www.kharchi.de/cppratgeber2.htm
-
@Artchi: Wo speichere ich dann meine Punkte, ich dachte die müsste ich mir mit Pointern merken?! Insbesondere die Nachbarschaft, bisher speichere ich mir einen Pointer, aber aus einem vector<Point> bekomme ich keinen Pointer.
Versteh ich nicht. Welche Pointer willst du? Von dem Vector? Oder von dem einzelnen Point? Für beide bekommst du den Pointer oder auch die Referenz, wenn du sie dir holst. Warum denn nicht?
Point *p1 = &(points.at(1)); // Pointer vom Point-ObjektAber einfach den Index merken, anstatt eines Pointers, wäre auch nicht verkehrt.
-
Danke für Eure Antworten. Ich mache es jetzt komplett ohne Pointer und es sieht echt um einiges besser aus. Habe da wohl doch noch nicht ganz die Verwendung von Pointern gerafft.
EDIT: Die Nachbarschaften speichere ich mir in zwei int-Variablen pro Point-Instanz.
Gruß
Patrick
-
Wenn ich mit einem Iterator durch einen Vektor iteriere :), kann ich dann irgendwie die Position im vector herausfinden? Also z.B. bla ist das fünfte Element im vector.
Gruß
Patrick
-
Ehm, eigentlich braucht man doch sowas nicht wissen, oder? Aber probier mal folgendes: Aktueller iterator minus begin. Wird aber vielleicht nicht funktionieren? Habs nie ausprobiert.
-
std::distance( x.begin(), myIt );Macht bei vector nichts anderes, als die beiden Iteratoren zu subtrahieren (also wie von Artchi vorgeschlagen). Hat allerdings den Vorteil dass es auch bei Iteratoren funktioniert die nicht Random-Access sind. In diesem Fall wird halt durchgezählt (der erste Iterator wird kopiert und solang inkrementiert bis er dem zweiten Iterator entspricht).