Problem mit Überladung von !
-
Vielleicht erst lernen was Zeiger und Referenzen sind, dann anfangen mit Operatorüberladungen rumzuspielen. Spart dir viel sinnlosen Ärger. :xmas1:
-
Die Anzahl der Beiträge sagt eben nicht viel über die Erfahrung aus. Da ich schon länger nicht mehr C++ programmiert habe, habe ich in der Tat Probleme mit Pointern.
Ich verstehe jedoch deinen Punkt nicht. Hier noch einmal der Code:
Bild* operator&(Bild* p) { return this; } Bild* b1 = new Bild(); Bild* b2 = new Bild(); b1 = b1 & b2;Der Operator & bekommt einen Zeiger auf ein Bild Objekt. b2 ist aber doch ein Zeiger. Daher sollte das nicht das Problem sein.
error: invalid operands of types ‘Bild*’ and ‘Bild*’ to binary ‘operator&’
Könnt ihr mir denn helfen bei der Fehlerbehebung?
Danke!
-
Könnt ihr mir denn helfen bei der Fehlerbehebung?
Ganz einfach, verzichte auf die Pointer.
Bild b1; Bild b2; b1 = b1 & b2; // et voilà
-
Das ist aber doof, weil die Funktionm, in der ich die Berechnungen durchführe ein Bild* zurückgibt. Somit könnte ich Bild Instanzen nicht mehr lokal anlegen. Wie sieht denn die Zeigerlösung aus?
-
Dann lass die Funktion halt keinen Pointer zurückgeben. Langsamer wird dein Code dadurch nicht (copy elision).
-
Bild* b1 = new Bild(); Bild* b2 = new Bild(); b1 = b1 & b2;Das Problem ist, dass du hier zwei Bild * mit dem Operator & verknüpfst. Der &-Operator ist aber für Bild * (und sonstige Pointer) nicht definiert. Du willst nicht die Pointer verunden, sondern die Bilder.
Bild* b1 = new Bild(); Bild* b2 = new Bild(); b1 = (*b1) & (*b2);b1 ist ein Pointer, (*b1) ist ein Bild, verunden von Pointern geht nicht, verunden von Bildern geht.
Bild* operator&(Bild* p) { return this; }Das sieht so aus, als wolltest du das Verunden zwischen Bild-Pointern definieren. Das geht nicht. Pointer sind eingebaut, eingebauten Datentypen kann man ihre Operatoren nicht überladen. Du musst schon den &-Operator für Bilder definieren, nicht für Bildpointer.
Bild operator&(const Bild &b){ Bild neuesBild = generiereIrgendwieNeuesBildAusThisUndb(this, &b); return neuesBild; }
-
Ersteinmal musst du natürlich nicht überall mit Zeigern rumhantieren, da haben die anderen Teilnehmer Recht, das hier ist halt kein Java, wo es keine andere Möglichkeit gibt.
Aber was mich jetzt wundert ist deine Argumentation, dass du operator! benutzen musst, weil du einen Term parsen willst, in dem ein ! vorkommt. Was hat denn das Parsen eines Quellcode-fernen Terms mit dem Aufbau des Quellcodes zu tun? Dir fliegt gerade wegen Deiner Affinität zu Zeigern deren implizite Konvertierbarkeit zum Typ 'bool' um die Ohren, da sollte man vielleicht nicht auch die ganzen Operatoren verwenden, die leider auch für bool definiert sind.
-
nwp3 schrieb:
Bild operator&(const Bild &b){ Bild neuesBild = generiereIrgendwieNeuesBildAusThisUndb(this, &b); return neuesBild; }Ich habe deine Idee mal versucht durchzuführen, aber leider haben sich meine Befürchtungen bewahrheitet. Bei dir ist nun das Problem, dass Du "neuesBild" zurückgibst, obwohl dieses eine lokale Variabel ist. Damit wird diese nach dem Ausführen der Funktion gelöscht und alles führt zu einem Segmentation Fault. Nun bringt es auch nichts "neuesBild" als Klassenvariabel einzuführen, weil die Operationen in verschiedenen Klassen durchgeführt werden. Kann man so überhaupt ganze Objekte zurückgeben?
Deswegen habe ich eben Zeiger benötigt.
Gibt es doch eine Lösung, wie ich dieses letzte Problem beheben kann oder muss ich doch auf Zeiger umsteigen?
Vielen Dank
LG, freakC++-
-
Ist doch egal, ob die Variable aus dem Scope geht, sie wird ja per Wert und somit als Kopie zurückgegeben. Es sei denn, du hast jetzt wieder einen Zeiger aus dem Rückgabewert gemacht...
-
freakC++ schrieb:
Bei dir ist nun das Problem, dass Du "neuesBild" zurückgibst, obwohl dieses eine lokale Variabel ist.
Das ist kein Problem, sondern völlig in Ordnung. Das Problem dürfte eher sein, dass die Bild-Klasse keinen ordentlichen Copy-Konstruktor hat.
-
freakC++ schrieb:
Ich verstehe jedoch deinen Punkt nicht. Hier noch einmal der Code:
Bild* operator&(Bild* p) { return this; } Bild* b1 = new Bild(); Bild* b2 = new Bild(); b1 = b1 & b2;Der Operator & bekommt einen Zeiger auf ein Bild Objekt. b2 ist aber doch ein Zeiger. Daher sollte das nicht das Problem sein.
error: invalid operands of types ‘Bild*’ and ‘Bild*’ to binary ‘operator&’
Hallo,
ich versuche dir mal zu erklären, warum das nicht geht:
1. Du hast eine Klasse definiert. D.h. du hast einen neuen Datentypen definiert.
2. Du hast innerhalb der Klasse den Operator&überladen.
3. Dein Datentyp heist Bild. D.h. du hast den Operator&für den Datentypen Bild überladen.
4. Du schaust dir den Datentyp vonb1undb2an. Du siehst, dass diese beiden Variablen vom TypBild*sind. Wir erinnern uns, dass du den Operator&für den TypBildüberladen hast. Und warum es nicht geht, dürfte dir jetzt ja klar sein:Datentyp Bild* != Datentyp Bild
-
Hallo zusammen,
vielen Dank für die zahlreichen Antworten. Ich habe nun Erfolg gehabt, indem zum einen einen korrekten Copy-Konstruktor definiert habe (der hatte tatsächlich noch gefehlt) und zum anderen ein "Bild" zurückgebe.
Dennoch verstehe ich nicht, warum diese Lösung nicht langsamer sein soll. Ich muss nun immer ein temporäres "Bild" anlegen, das dan zurückgeben wird. Wir bei mir nun nicht ziemlich viel hin und her kopiert. Dieses Problem müsste man mit Zeigern doch eigentlich umgehen, oder?
Vielen Dank
LG, freakC++
-
freakC++ schrieb:
Ich habe nun Erfolg gehabt, indem zum einen einen korrekten Copy-Konstruktor definiert habe (der hatte tatsächlich noch gefehlt) und zum anderen ein "Bild" zurückgebe.
Hast meinen Link angeschaut? Modern C++. Sofern Bild richtig designt ist (keine internen Zeiger), dürfte es nicht nötig sein, einen Kopierkonstruktor zu schreiben. Poste am besten einmal deine Klasse Bild oder zumindest ihre Membervariablen.
freakC++ schrieb:
Ich muss nun immer ein temporäres "Bild" anlegen, das dan zurückgeben wird. Wir bei mir nun nicht ziemlich viel hin und her kopiert. Dieses Problem müsste man mit Zeigern doch eigentlich umgehen, oder?
Das Problem wird schon umgangen, aber nicht mit Zeigern.
Zum einen wäre da die Copy Elision, die ich schon genannt habe, du aber scheinbar überlesen hast. Schau mal da: Want Speed? Pass by Value.
Zum anderen gibt es mit C++11 nun RValue-References.
-
Was man hier noch machen könnte wäre "copy on write shared data". Das verwendet z.B. Qt intern bei sehr vielen Klassen. Ob sich das bei dir lohnt und ob das Sinn macht, weiß ich nicht. In dem konkreten Beispiel von dir sollte copy elision in der Tat reichen. Vielleicht hast du aber noch mehr Use Cases für die Klasse, wo sich shared data dann lohnen würde.
-
-
kuh schrieb:
Ja, der Aspekt ist nicht neu. Der Artikel ja auch nicht, er ist von 1999. Bei Qt ist es wohl halbwegs unproblematisch:
http://doc.qt.digia.com/qt/threads-modules.html#threads-and-implicitly-shared-classes
Ich denke, wenn man das richtig benutzt, sollte es keine Performance Probleme geben.
-
freakC++ schrieb:
Hallo zusammen,
vielen Dank für die zahlreichen Antworten. Ich habe nun Erfolg gehabt, indem zum einen einen korrekten Copy-Konstruktor definiert habe (der hatte tatsächlich noch gefehlt) und zum anderen ein "Bild" zurückgebe.
Dennoch verstehe ich nicht, warum diese Lösung nicht langsamer sein soll. Ich muss nun immer ein temporäres "Bild" anlegen, das dan zurückgeben wird. Wir bei mir nun nicht ziemlich viel hin und her kopiert. Dieses Problem müsste man mit Zeigern doch eigentlich umgehen, oder?
Vielen Dank
LG, freakC++Bild funktion() { Bild bild; baue_bild(bild); return bild; } Bild bild = funktion();baut dir jeder Compiler um zu
Bild* funktion(void* buf) { new (buf) Bild; baue_bild(*buf); return buf; } Byte bild[sizeof(Bild)]; funktion(bild);
-
Befasse Dich bitte nochmal mit der Semantik von Operatoren. Wenn Du schreibst a = b & c, dann erwartest Du doch in a das Ergebnis der Operation aus b und c. Darüberhinaus erwartest Du, dass b und c unverändert bleiben, denn sonst würdest Du b &= c schreiben. Also musst Du doch in jedem Fall ein neues Objekt anlegen, welches das Ergebnis der Operation darstellt. Das ändert sich auch durch die Benutzung von Zeigern nicht.
Weiterhin sollte ein binärer Operator links- und rechtsseitig den gleichen Typen erwarten. Da Dein Operator ein Member der Klasse Bild ist, ist der linksseitige Typ Bild& (oder wenn die Methode const-qualifiziert ist Bild const&, und das sollte so sein, da Du ja, wie oben angedeutet, b und c nicht verändern willst). Deshalb sollte auch der Parameter der Methode Bild const& und nicht Bild* sein.
Und wenn Du Zeiger hast, musst Du sie für die Anwendung von Operatoren dereferenzieren, da alle Operatoren für Zeiger (also T* op T*) bereits von der Sprache vorgegeben und nicht veränderbar sind.
-
freakC++, dein Design schreit nach Speicherlecks. Ich kann das nur nochmal wiederholen, dass das, was in dem von hier aus verlinkten PDF ("Modern C++") steht, beherzigt werden sollte. Wenn du nicht selbst drauf kommst (und das wäre ja keine Schande!), warum das alles gute Ideen sind, frag' einfach nach.
Was ist eigentlich der Sinn der Klasse BildMama? Wozu ist die da? Hast Du vor, mehrere Datenstrukturen mit ein und derselben "BildMama"-Schnittstelle für den Datenzugriff auszustatten? Ich würde das lieber so wie die STL regeln. Das hieße, man baut sich so etwas ähnliches wie einen Iterator halt nur für 2D. std::vector<T> leitet ja auch nicht von sequenz<T> oder sowas ab. Wenn man dann die "dynamische Polymorphie" braucht, kann man sie immer noch bekommen, indem man beliebige "2D-Iteratoren" in einem Objekt wrappt, was dann von irgendwas ableitet.