Benennung von "Accessors"
-
Brot, das wär toll, würde ich mir gerne mal durchlesen!
Edit: Ich sehe ein, dass worüber Dravere, Nexus und ich gerade diskutieren inzwischen etwas am Thema des Threads vorbeigeht, aber das Thema wird ganz schnell wieder Aktuell, sobald ich die Accessor-Idee verwerfen muss

-
@Decimad,
Schon mal nicht schlecht und nun noch das Problem mitthislösen. Wenn du den Wert nicht in den Accesor reinnimmst, wird das wahrscheinlich recht problematisch. Wahrscheinlich muss die Klasse, welche den Accessor benutzt, dies machen. Wodurch man nicht mehr den Standard-Kopierkonstruktor verwenden darf, was wieder ein zusätzliches Ärgernis darstellt.Nexus schrieb:
Dravere schrieb:
Du vergisst hier aber, dass man keine Kontrolle über Zeitpunkte hat. Wird die Funktion jetzt davor oder danach aufgerufen? Kann ich die Zuweisung verhindern, wenn ein falscher Wert übergeben wird? Am Ende hast du dann 4 Funktionen als Templateparameter?
Ich verstehe nicht ganz, was du meinst. Im Grunde leitet man einfach den
operator=an eine Setter-Funktion weiter, dort kann man auch Wertprüfungen etc. durchführen.Ok, wir müssen uns hier wohl schnell auf eine Lösung einigen. Wird nun der Wert im Accessor gespeichert, wie du dies auf Seite 1 vorgeschlagen hast oder wird er in der Klasse
Testgespeichert?Nexus schrieb:
Dravere, bitte nicht schon wieder. So langsam sollten wir das geklärt haben.
Nexus schrieb:
Du hast die Angewohnheit, vorschnell Schreibfaulheit in ein Argument hineinzuinterpretieren.
Naja, stimmt es denn nicht? Ich habe einfach so leichte Mühe, wenn jemand eine zusätzliche Schreibarbeit von Sekunden bemängelt, welche den Code auch gar nicht unübersichtlicher macht.
Nexus schrieb:
Dravere schrieb:
Die Kopie hast du auch so. Der Kompiler optimiert dies weg.
Nein, das stimmt nicht. Bei
Size size = obj.GetSize(); obj.SetSize(2 * size);hast du ein Objekt
size, das immer erstellt wird. Wenn die FunktionGetSize()eine Const-Referenz zurückgibt, hast du hingegen beiobj.SetSize(2 * obj.GetSize())keine Kopie der Originalgrösse.
Nö. Es gibt nach meinem Wissen keine Vorschrift für den Kompiler, dass er diese Kopie durchführen muss. Zusätzlich kann man auch eine Referenz auf ein konstantes Objekt als Typ anwenden, egal ob eine konstante Referenz zurückgegeben wird:
Size const& size = obj.GetSize(); // Darf gerne "Size GetSize();" sein. obj.SetSize(2 * size); // Dies ist absolut erlaubt.Die Lebzeit des temporären Objektes wird hier einfach verlängert. Und wenn es eine konstante Referenz zurückgibt, dann ist es ja gut ...
Nexus schrieb:
Dravere schrieb:
Implizite Konvertierungen kannst du mit explicit gut verhindern.
Man soll sie ja nicht verhindern, sondern immer ausserhalb der Klasse aktivieren, und nie innerhalb (für Verwaltungsaufgaben wie Kopien).
Da verstehe ich dich nicht.
Nexus schrieb:
Dravere schrieb:
Aber das mit dem operator() musst du mir erklären. Willst du dann dies einbauen?
Nein, statt
text.xhalttext.x(). Ist hässlich, aber vielleicht die einzige Möglichkeit.Und worin liegt nun den Unterschied dazu, dass man eine Funktion x als Getter anbietet? Oder gleich
test.get_x()hinschreibt?
Nexus schrieb:
Okay. Mir ist es halt so vorgekommen, als handle es sich um eine prinzipielle Abneigung gegen Sprachmittel-Übernahmen. Gerade auch weil du im ersten Beitrag eigentlich keine Argumente gebracht hast.
Da war ich nur schreibfaul

Grüssli
-
Dravere schrieb:
Ich habe einfach so leichte Mühe, wenn jemand eine zusätzliche Schreibarbeit von Sekunden bemängelt, welche den Code auch gar nicht unübersichtlicher macht.
Ich habe nirgends die Schreibarbeit bemängelt, das hast du mir wieder mal unterstellt.
Vielmehr habe ich grundsätzlich etwas gegen unnötig viel Code. Bei mir geht Einfachheit vor, sofern dadurch keine wesentlichen Nachteile entstehen. Und nicht selten sehe ich mit weniger Code auch schneller, was passiert (damit meine ich keine Abkürzungen, wobei es auch da sinnvolle gibt). Und hier ist es meiner Meinung nach so, dass die lokalen Variablen keinen wirklichen Vorteil bringen, daher lasse ich sie weg. Aber bei wirklich komplexen Ausdrücken mach ichs auch wie du. Bei mir ist halt die Grenze, wo ich durch die Auslagerung einen Gewinn sehe, etwas weiter entfernt als bei dir.
Hat zwar mit dem Beispiel nicht mehr viel zu tun, aber mir ist gerade noch ein Vorteil von temporären Ausdrücken eingefallen: Bei
&&und||muss nicht alles ausgewertet werden.Dravere schrieb:
Nö. Es gibt nach meinem Wissen keine Vorschrift für den Kompiler, dass er diese Kopie durchführen muss.
Doch, die gibt es. Kopien dürfen nur genau in zwei Situationen wegoptimiert werden: Bei temporären Objekten und Rückgabewerten von Funktionen.
Dravere schrieb:
Zusätzlich kann man auch eine Referenz auf ein konstantes Objekt als Typ anwenden, egal ob eine konstante Referenz zurückgegeben wird
Ja, so würde ichs auch tun. Ich habe auch kein Problem damit, bei grösseren Objekten eine Const-Referenz als Rückgabetyp zu verwenden. Aber ich habe schon anderes gehört...
Übrigens: Fang nicht auch noch an mit "konstanten Referenzen" :p
Zu den
Accessor-spezifischen Dingen: Ich hab mir da keine konkrete Implementierung gebastelt, das sind mehr ein paar Vorstellungen. Mit den impliziten Konvertierungen habe ich gemeint, dass sie dann erwünscht sind, wenn die Property von ausserhalb der Klasse benutzt wird (als Getter), und dann sollen sie immer in Kraft treten. Jedoch ist das manchmal schwierig:template <typename T> void DoSomething(T t); DoSomething(obj.Size); // Da der erste Parameter ein Template-Typ-Parameter ist, wird nie eine // Konvertierung vorgenommen. Man übergibt also das Proxy statt der Grösse
-
Nexus schrieb:
Vielmehr habe ich grundsätzlich etwas gegen unnötig viel Code. Bei mir geht Einfachheit vor, sofern dadurch keine wesentlichen Nachteile entstehen. Und nicht selten sehe ich mit weniger Code auch schneller, was passiert (damit meine ich keine Abkürzungen, wobei es auch da sinnvolle gibt). Und hier ist es meiner Meinung nach so, dass die lokalen Variablen keinen wirklichen Vorteil bringen, daher lasse ich sie weg. Aber bei wirklich komplexen Ausdrücken mach ichs auch wie du. Bei mir ist halt die Grenze, wo ich durch die Auslagerung einen Gewinn sehe, etwas weiter entfernt als bei dir.
Ich mag verschachtelte Funktionen nicht. Sowas empfinde ich als sehr mühsam zum Lesen. Daher sind für mich die zusätzlichen Variablen eine Vereinfachung des Codes. Ich verschachtle sogar nur sehr ungern die Properties aus C#.
Nexus schrieb:
Dravere schrieb:
Nö. Es gibt nach meinem Wissen keine Vorschrift für den Kompiler, dass er diese Kopie durchführen muss.
Doch, die gibt es. Kopien dürfen nur genau in zwei Situationen wegoptimiert werden: Bei temporären Objekten und Rückgabewerten von Funktionen.
Standard, Kapitel, Absatz? Tut mir Leid, aber sonst kauf ich dir das nicht ab, denn das wäre mir ganz neu. Wieso sollte es verboten sein, unnötige Kopien ohne Nebeneffekte wegzuoptimieren?
Nexus schrieb:
Ja, so würde ichs auch tun. Ich habe auch kein Problem damit, bei grösseren Objekten eine Const-Referenz als Rückgabetyp zu verwenden. Aber ich habe schon anderes gehört...
Ich bin mir nicht ganz sicher, ob du da mein Argument richtig verstanden hast. Es ging mir in erster Linie darum, wenn jemand keine "Const-Referenz" zurückgibt, dass man dann trotzdem die Variable als "Const-Referenz" empfangen kann:
class Rectangle { public: Size getSize() const; }; // ... Size const& size = client_rectangle.getSize(); // mit size arbeiten.Nexus schrieb:
Übrigens: Fang nicht auch noch an mit "konstanten Referenzen" :p
Ja, ja, ich weiss. Deshalb habe ich es vor dem Komma noch so umständlich umschreiben und nach dem Komma keine Lust mehr gehabt. Sollen wir eine Abkürzung einführen?

RAKO - Referenz Auf Konstantes ObjektNexus schrieb:
Zu den
Accessor-spezifischen Dingen: Ich hab mir da keine konkrete Implementierung gebastelt, das sind mehr ein paar Vorstellungen. Mit den impliziten Konvertierungen habe ich gemeint, dass sie dann erwünscht sind, wenn die Property von ausserhalb der Klasse benutzt wird (als Getter), und dann sollen sie immer in Kraft treten. Jedoch ist das manchmal schwierig:Ich habe jetzt mit dem
explicitnicht unbedingt den Konvertierungsoperator gemeint, sondern eher einen Konstruktor. Wenn man nämlich den Wert inAccessorspeichert, dann wäre es sinnvoll eine Initialisierung anzubieten. Dieser Konstruktor müsste man zwingend aufexplicitsetzen, da sonst andere Unschönheiten passieren. Ich würde sowieso alle Konstruktoren in der KlasseAccessoraufexplicitsetzen. Man wird darauf ja auch kaum anders als explizit zugreifen.Grüssli
-
Dravere schrieb:
Standard, Kapitel, Absatz? Tut mir Leid, aber sonst kauf ich dir das nicht ab, denn das wäre mir ganz neu.
Man kann immer dazulernen. Aber weil du mir nicht glaubst:
12.8/15 Copying class objects schrieb:
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.111) This elision of copy operations is permitted in the following circumstances (which may be combined to eliminate multiple copies):
— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value
— when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copyDravere schrieb:
Wieso sollte es verboten sein, unnötige Kopien ohne Nebeneffekte wegzuoptimieren?
Weil sie relevante Nebeneffekte haben könnten.
-
Nexus schrieb:
12.8/15 Copying class objects schrieb:
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects.
Und wo steht da, dass es verboten ist, den Kopierkonstruktor auszulassen, wenn er keine Seiteneffekte hat?
Eine Klasse ist gut, wenn sie den Kopierkonstruktor vom Kompiler bekommen hat und nur aus pod-Typen oder guten Klassen besteht (Achtung: Rekursion). Ist es verboten, die Kopien von guten Klassen zu wegoptimieren?
-
dazulerner schrieb:
Und wo steht da, dass es verboten ist, den Kopierkonstruktor auszulassen, wenn er keine Seiteneffekte hat?
Da steht, die Kopie darf nur weggelassen werden, wenn die beiden Kriterien erfüllt sind. "Nur", weil Kopierkonstruktoren normalerweise nicht wegoptimiert werden und hierfür extra eine Sonderregel im C++-Standard eingerichtet worden ist.
Dem entnehme ich, dass die Optimierung in den anderen Fällen streng genommen nicht erlaubt ist, auch wenn keine Seiteneffekte vorhanden sind. Dies ist zumindest meine Auslegung des Paragraphen. Wie Compiler das umsetzen, ist dann ohnehin wieder ein anderes Thema.
-
@Dravere, ohne wirklich richtig zu cheaten (weil es sozusagen wirklich stimmt) könnte man den Byteoffset des Member-Accessors mitgeben, dann kann der sich aus seinem eigenen this-Zeiger den des umliegenden Objekts errechnen. Fällt mir gerade so ein. Ist natürlich unschön, aber sieht nachher niemand mehr^^
Edit: Vielleicht würde ein guter Compiler dann ach die Ausdrücke x+offset-offset erkennen, die da dann immer auftauchen und sie gleich ganz eliminieren...
-
Nexus schrieb:
Zu den
Accessor-spezifischen Dingen: Ich hab mir da keine konkrete Implementierung gebastelt, das sind mehr ein paar Vorstellungen. Mit den impliziten Konvertierungen habe ich gemeint, dass sie dann erwünscht sind, wenn die Property von ausserhalb der Klasse benutzt wird (als Getter), und dann sollen sie immer in Kraft treten. Jedoch ist das manchmal schwierig:template <typename T> void DoSomething(T t); DoSomething(obj.Size); // Da der erste Parameter ein Template-Typ-Parameter ist, wird nie eine // Konvertierung vorgenommen. Man übergibt also das Proxy statt der GrösseDa hast du natürlich recht, das würde zu vielen unnötigen Template-Instanziierungen führen. Grumpf.
Edit: Snip. Stimmt natürlich gar nicht, es kann ja in der Form keine freien Instanzen von den Accessor-Objekten geben, aber dein Beispiel gilt natürlich analog für Referenzen.
-
Nexus schrieb:
Dem entnehme ich, dass die Optimierung in den anderen Fällen streng genommen nicht erlaubt ist, auch wenn keine Seiteneffekte vorhanden sind.
Doch, Optimierungen sind immer erlaubt. Die einzige Forderung ist, dass das Programm sich nach außen hin so verhält, wie es spezifiziert ist. Die Sonderregel mit dem Kopierkonstruktor besagt, dass in gewissen, genau festgelegten Fällen Kopierkonstruktoren wegoptimiert werden dürfen, selbst wenn sich dadurch Änderungen im beobachtbaren Verhalten ergeben.
-
So macht das natürlich Sinn. Danke für die Erklärung!
-
Decimad schrieb:
@Dravere, ohne wirklich richtig zu cheaten (weil es sozusagen wirklich stimmt) könnte man den Byteoffset des Member-Accessors mitgeben, dann kann der sich aus seinem eigenen this-Zeiger den des umliegenden Objekts errechnen. Fällt mir gerade so ein. Ist natürlich unschön, aber sieht nachher niemand mehr^^
Edit: Vielleicht würde ein guter Compiler dann ach die Ausdrücke x+offset-offset erkennen, die da dann immer auftauchen und sie gleich ganz eliminieren...Meinst du dies jetzt als Lösung wegen dem Problem mit
this? Dann ist deine Idee alles andere als sinnvoll. Das Programm greift schliesslich selber bereits genau so drauf zu. Da ändert es nichts, ob man nun selber über den Offset geht oder der Kompiler dies überthisfür einem ausrechnet. Es bleibt undefiniertes Verhalten.
Eine Möglichkeit, was passieren könnte, ist, dass du über den Offset die Speicherstelle beschreibst, da die Klasse aber noch nicht vollständig initialisiert ist, wird der Speicherbereich dann vom eigentlichen Konstruktor erneut überschrieben und deine Initialisierung geht flöte.Definitiv keine gute Idee ...
@Nexus,
Deswegen können eben C und C++ Kompiler so aggressiv optimieren, weil es grundsätzlich keine Verbote gibt. Und die Regel ist eben nur eine Hilfe für zusätzliche Optimierungen. C++ ist voll darauf ausgelegt, dass optimiert werden kann ohne Ende.Grüssli
-
@Dravere, du hast mich offenbar missverstanden. Ich wollte damit nicht das "zu frühe" Verwenden von "this" umgehen, sondern den Speicherplatz für this_ im Accessor einsparen (womit sich auch komplett die zu frühe Benutzung erübrigt, weil der Accessor nicht mehr die Laufzeit-Hilfe der beinhaltenden Klasse benötigt).
-
Eigentlich war mir diese Grundsatzregel mit dem Optimieren bekannt, doch da der Standard sich im Bezug auf Kopierkonstruktoren so explizit ausdrückte, hielt ich das für bindend. Von der Grundsatzregel habe ich hingegen nie was Offizielles gelesen...
Abgesehen davon weiss ich nicht, wie offensiv heutige Compiler sind. Aber auf die "guten" Klassen von dazulerner wird es wohl schon zutreffen. Dennoch wäre ich vorsichtig mit dem Spekulieren auf Kopier-Optimierungen, sobald der Einfluss auf die Performance wesentlich wird.
-
Decimad schrieb:
@Dravere, du hast mich offenbar missverstanden. Ich wollte damit nicht das "zu frühe" Verwenden von "this" umgehen, sondern den Speicherplatz für this_ im Accessor einsparen (womit sich auch komplett die zu frühe Benutzung erübrigt, weil der Accessor nicht mehr die Laufzeit-Hilfe der beinhaltenden Klasse benötigt).
Kannst du mir das zeigen, wie du das machen willst?
Ich zweifle sehr, dass du dies definiert hinbekommst.Nexus schrieb:
Dennoch wäre ich vorsichtig mit dem Spekulieren auf Kopier-Optimierungen, sobald der Einfluss auf die Performance wesentlich wird.
Da stimme ich dir zu.
Grüssli
-
Leider gar nicht, aber im Prinzip wüsste der Compiler es ja, schade nur, dass er es uns für nicht POD-Klassen nicht sagen mag.
Also bei konformer C++-Benutzung ist man auf diesen this_-Zeiger angewiesen.
Aber ich meine in Boost sogar schonmal solche nicht-Standardkonformen Pro-Compiler-Optimierungen gesehen zu haben.
-
Nexus schrieb:
Eigentlich war mir diese Grundsatzregel mit dem Optimieren bekannt, doch da der Standard sich im Bezug auf Kopierkonstruktoren so explizit ausdrückte, hielt ich das für bindend. Von der Grundsatzregel habe ich hingegen nie was Offizielles gelesen...
1.9§5:
"A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible execution sequences of the corresponding instance of the abstract machine with the same program and the same input. [...]"Fußnote: "This provision is sometimes called the «as-if» rule, because an implementation is free to disregard any requirement of this International Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program. [...]"
-
Ah, alles klar. Danke.
