Wieso operator + mit += implementieren??
-
zuerst sagte ich wie du richtig herausgestellt hast, dass der op+ so wie er da stand nicht ausserhalb einer klasse definiert werden kann-es fehlte halt das berühmte buzzword "friend",welches aber in der nachfolgenden beispielimplementierung nicht nachgeliefert wurde, währe da ein friend gekommen hätt ich gesagt: "ok alles in ordnung sorry für den kommentar", aber nein, stattdessen wurden mir wunderbare public variablen angeboten, die-und das kannst du nicht abstreiten- in diesem fall eindeutig das OCP verletzt haben, womit die implementierung des op+ sofort schlechter wird als die ocp unterstützende benutzung des op += innerhalb des op+,und darum gings ja auch in dem thread, was besser ist, oder? Du beschäftigst dich mit der funktionalität, ich mich mit der Kapselung (weshalb ich auch normalerweise friend operatoren vermeide btw)
Und wehe, jetzt geht hier ein flamewar los, was kapselung mit dem OCP zu tun hat^^
-
@Threadersteller: Warum postet du nicht mit deinem richtigen Nick "nix da"? Sind dir die Fragen zu peinlich?
-
otze schrieb:
zuerst sagte ich wie du richtig herausgestellt hast, dass der op+ so wie er da stand nicht ausserhalb einer klasse definiert werden kann-es fehlte halt das berühmte buzzword "friend",welches aber in der nachfolgenden beispielimplementierung nicht nachgeliefert wurde, währe da ein friend gekommen hätt ich gesagt: "ok alles in ordnung sorry für den kommentar", aber nein, stattdessen wurden mir wunderbare public variablen angeboten, die-und das kannst du nicht abstreiten- in diesem fall eindeutig das OCP verletzt haben, womit die implementierung des op+ sofort schlechter wird als die ocp unterstützende benutzung des op += innerhalb des op+,und darum gings ja auch in dem thread, was besser ist, oder? Du beschäftigst dich mit der funktionalität, ich mich mit der Kapselung (weshalb ich auch normalerweise friend operatoren vermeide btw)
Und wehe, jetzt geht hier ein flamewar los, was kapselung mit dem OCP zu tun hat^^
Was hat Kapselung mit dem OCP zu tun?
-
Hier herrscht ein Tonfall.... wie im Kindergarten
-
MDas ist ne faustregel, mehr nicht. Gibt genügend Fälle wo das nicht so ist - aber: Wenn man operator+ "direkt" implementiert, sollte man triftige Gründe haben.
-
Gründe für die Faustregel
a.operator+=(b) sollte das gleiche Ergebnis haben wie a=a+b Die Arithmertik dafür sollte an einer Stelle liegn /Reduktion der Fehlerquellen, Stellen für Modifikationen)
Nun hat man die Wahl, operator+ mit Hilfe von += zu implementieren - oder andersherum. Variante 1 ist simpel, Variante 2 dämlich: erstens hat += von Natur aus Zugriff auf Klasseninterna, operator+ als nur assoziierte Funktion aber nicht. Zweitens braucht operator+ im Normalfall sowieso eine temp-Variable, die die mögliche bessere performance von += verdirbt. Außerdem ist der + - Operator komplexter (drei statt zwei entities), also die Gefahr eines Fehlers deutlich höher.
Wie schlimm ist also die zweite temporäre variable?
Wenn der Konstruktor "teuer" ist, sollte operator+ an Performance-kritischen Stellen sowieso vermieden werden. Ist der Konstruktor primitiv, kann der Optimizer den größten Teil des overheads rausschmeißen.In deinem Beispiel: operator+ über += imkplementiert benötigt 12 ASM-Befehle, die "Handimplementation" 9 von ähnlicher Komplexität. Die erhöhten Entwicklungskosten lohnen sich also nur, wenn die Klasse hochkritisch ist und die Kosten des Copy- bzw. Memberassign-Konstruktors in der gleichen Größenordnung wie += liegen.
-
-
otze schrieb:
Du beschäftigst dich mit der funktionalität, ich mich mit der Kapselung (weshalb ich auch normalerweise friend operatoren vermeide btw)
Wenn du Kapselung nicht nur so als Begriff verwenden würdest, sondern dich mit dem Konzept dahinter beschäftigen würdest, würdest du feststellen, dass friend keinerlei negative Einwirkungen auf die Kapselung hat (nicht mehr als eine Methode auch). Besonders wenn es sich nicht um ein "long distance friendship" handelt.
Und wehe, jetzt geht hier ein flamewar los, was kapselung mit dem OCP
zu tun hat^^Es ging hier nicht um einen flamewar sondern um eine Diskussion. Aber mit dir zu diskutieren scheint eh sinnlos, da du nicht mal versuchst etwas sinnvolles beizutragen.
-
friend und encapsulation:
http://www.parashift.com/c++-faq-lite/friends.html
"Do friends violate encapsulation? No! If they're used properly, they enhance encapsulation."siehe auch: http://www.gotw.ca/gotw/070.htm
"Get your interfaces right first. Internals are easy enough to fix later, but if you get the interface wrong you may never be allowed to fix it."http://www.gotw.ca/gotw/004.htm (class Complex)
"operator+ should not be a member function. If it's a member like this, you can write "a=b+1" but not "a=1+b"."
op+= als Member-Funktion, op+ wird außerhalb der Klasse realisiert und verwendet intern op+=:const Complex operator+( const Complex& lhs, const Complex& rhs ) { Complex ret( lhs ); ret += rhs; return ret; }
Bei boost::rational wird op+= ebenfalls als Member-Funktion realisiert, op+ ist im header rational.hpp überhaupt nicht aufgeführt, soweit ich das erkennen kann. Muss irgendwie anders realisiert sein, konnte leider nicht genau erkennen wie. Vielleicht weiß das jemand genau?
zu op+ und op+= siehe auch: http://coding.derkeiler.com/Archive/C_CPP/comp.lang.cpp/2003-10/2715.html
otze hat übrigens dort Recht, wo er behauptet, dass Zähler und Nenner private sein sollten. Das war, soweit ich das erkennen konnte, sein Hauptziel. Er hat auch ausgeführt, dass op+ außerhalb der Klasse realisiert werden soll.
Allgemein zum Optimieren:
http://www-2.cs.cmu.edu/~gilpin/c++/performance.html#temporaries
dort findet sich ebenfalls:
"Temporaries can be avoided by using <op>= operators. For example, the code
a = b + c;
could be written as
a=b;
a+=c;."PS: Der nichtregistrierte Fragesteller hat hier einen Ton angeschlagen, der in keinster Weise zur Komplexität der Frage passt. Daher sollte man zumindest auch im Forum C++ nur registrierte Nutzer zulassen, damit dieser Mischung aus primitivem Getrolle (das jeder gut versteht und entsprechend emotional reagiert) und Fachchinesisch (das nicht jeder versteht, z.B. OCP, RVO, NRVO, ..., und daher Missverständnisse und Unklarheiten die Folge sind) ein baldiges Ende beschert sein möge. Dann sollte es wieder möglich sein, fachliche Fragen vorwiegend fachlich zu diskutieren. Humor ist allerdings erlaubt.
-
Da ja nun geklärt ist, das man den op+ über op+= implementiert
hab ich mal 'ne Frage an die Profis. Zur Auswahl stehen zwei op+ Implementierungen:
foo operator +(const foo& lhs, const foo& rhs) { return foo(lhs) += rhs; }
foo operator +(foo lhs, const foo& rhs) { return lhs += rhs; }
Variante 1 kann mein Compiler teilweise besser optimieren. Allerdings kann es uU Compilerfehler geben, wenn die Klasse aligned ist. Wohin schlägt also das Pendel: 1, 2 oder sollte man von Fall zu Falls unterscheiden?
// edit
Hoppla, da ist mir doch beim Kopieren ein dummer Fehler unterlaufen.
-
groovemaster2002 schrieb:
Variante 1 kann mein Compiler teilweise besser optimieren. Allerdings kann es uU Compilerfehler geben, wenn die Klasse aligned ist.
Kannst Du das genauer erklären?
Ich verwende grundsätzlich Variante 1, weil sie ohne irgendwelche Tricks und Schnörkel einfach funktioniert. (+ ist normalerweise symmetrisch, also sollten auch die Parameter auf die selbe Art übergeben werden. Von einem Problem mit dieser Variante habe ich noch nie was gehört.
MfG Jester
-
Variante 1 ist vorzuziehen:
Wenn der Compiler entscheidet, die Funktion nicht zu inlinen, ist der Aufruf "billiger".Alignment? Wenn das Quellobjekt falsches Alignment hat, dann hast Du die Probleme sowieso beim erstellen der Kopie. Oder was meinst du?
-
peterchen schrieb:
Variante 1 ist vorzuziehen:
Wenn der Compiler entscheidet, die Funktion nicht zu inlinen, ist der Aufruf "billiger".Wo Du die Kopie ziehst ist doch letztlich egal, oder?
-
Jester schrieb:
peterchen schrieb:
Variante 1 ist vorzuziehen:
Wenn der Compiler entscheidet, die Funktion nicht zu inlinen, ist der Aufruf "billiger".Wo Du die Kopie ziehst ist doch letztlich egal, oder?
bei einem aufruf ja. bei 1000 aufrufen wäre ich geneigt, die kopie lieber im op+ zu ziehen, als 1000 mal außerhalb.
-
Einfach mal John Potters Erklärung lesen. Dazu noch den nächsten Beitrag von Daniel Frey.
Variante 1 ist die schlechteste Alternative.
Am Besten:const foo operator +(const foo& lhs, const foo& rhs) { foo rv(lhs); rv += rhs; return rv; }
Das finde ich wirklich mal toll: Der Code, der am Besten zu lesen ist und am wenigsten nach "besonders-clever" aussieht, ist gleichzeitig auch der effizienteste.
<edit>Tippfehler in Rückgabewert korrigiert!
Natürlich liefert der op+ sein Ergebnis als Wert und nicht als Referenz.</edit>
-
referenz auf ein temporary?
Klar, man spart sich eine Kopie, dafür muß man jedem Nutzer einbleuen, sofort eine Kopie zu ziehen... Effektiver, aber gefährlicher. Würde ich nicht als "am besten" bezeichnen.Ich seh auch an Herrn Potters Erklärungen a) keine anderen Varianten und b) keine Vorteile. Oder hab ich was übersehen?
-
peterchen schrieb:
referenz auf ein temporary?
tippfehler.
-
HumeSikkins schrieb:
Einfach mal John Potters Erklärung lesen. Dazu noch den nächsten Beitrag von Daniel Frey.
Variante 1 ist die schlechteste Alternative.
Am Besten:foo& operator +(const foo& lhs, const foo& rhs) { foo rv(lhs); rv += rhs; return rv; }
Hier wird doch ne Refernz auf ne lokale Var. zurückgegeben. Ist das nicht illegal?
-
interpreter und peterchens Beitrag, sowie dieser haben sich erledigt.
-
Ich dachte, Volkard hatte sich verschrieben
-
HumeSikkins schrieb:
Am Besten:
foo& operator +(const foo& lhs, const foo& rhs) { foo rv(lhs); rv += rhs; return rv; }
Ich hoffe dir ist aufgefallen das eine Warning geworfen wird bei dem code:
main.cpp(54) : warning C4172: returning address of local variable or temporary
-
Ja, genau darüber wurde in den letzten 4 Beiträgen gesprochen. Es handelt sich um einen Tippfehler, das & im Typ des Rückgabewerts muß weg.
-
Jester schrieb:
Ja, genau darüber wurde in den letzten 4 Beiträgen gesprochen. Es handelt sich um einen Tippfehler, das & im Typ des Rückgabewerts muß weg.
lol sorry habs überlesen