Kopierkonstruktor, Zuweisungsoperator
-
Dynamic(int val=0, int size = 0);
ist doch ein schöner default konstruktor...Ups, die default-values uebersehen, stimmt
wieso nicht ? welche sicherheit gibt dieses zusätzlich const? im übrigen gibt der operator für built-in typen ebenfalls non-const lvalues zurück.
nicht wirklich einen, weil selbst bei der normalen verkettung der compiler das anders aufloesst ....
x = y = z; ist kein problem oder ?
aber:
(x = y) = z;
Was macht das fuern sinn ? woelltest du das compilieren koennen ?Ciao ...
-
camper schrieb:
arraySize = rhs.arraySize;hier wird arr nicht reallokiert. schlecht wenn rhs.arraySize grösser als der verherige wert von arraySize war...
Ich versteh nicht so richtig was mit dieser Zeile nicht in Ordnung ist. Könnt ihr mir das vielleicht ein bißchen genauer erklären?
-
Es ist so wie camper schon geasgt hat. Du gibst arraySize einen neuen wert, änderst aber die grösse von arr nicht. Eigentlich müsstest du arr zuerst freigeben und dann mit der neuen Grösse neu anlegen.
Kurt
-
Wäre das so korrekt?
Dynamic& Dynamic::operator=(const Dynamic& rhs) { if(this == &rhs) return *this; value = rhs.value; arraySize = rhs.arraySize; delete[]arr; arr = new int[arraySize]; for(int i=0; i<arraySize; i++) { arr[i] = rhs.arr[i]; } id=rhs.uniqueObjId; return *this; }
-
So sollte es funktionieren.
Natürlich musst du das array nicht löschen und neu anlegen wenn
rhs.arraySize <= arraySize. Finde es aber besser so.
Kurt
-
RHBaum schrieb:
aber:
(x = y) = z;
Was macht das fuern sinn ?Keinen wirklichen. Wer macht aber auch sowas?
RHBaum schrieb:
woelltest du das compilieren koennen ?
Durchaus. Mit primitiven Typen funktioniert das ja auch.
Sofern es keinen trifftigen Grund gibt, sollte op= imo foo& zurückgeben, und nicht const foo&. Damit ist das Handling intuitiv so wie bei primitiven Typen.
-
warum wird eigentlich zweimal der Destruktor aufgerufen?
-
Damit ist das Handling intuitiv so wie bei primitiven Typen.
Vielleicht isses ja meine rebellische Natur
aber grad bei den zuweisungsoperatoren find ich es uberhaupt nicht intuitiv .... liegt sicher auch daran, dass die faelle , wo es ueberhaupt greifen wuerde, soweiso keiner "macht"bei den anderen binaeren verkettenbaren operatoren hasst natuerlich vollkommen recht ...
Nur weil es bei den Pods geht, soll es mit meinen Klassen auch gehen, obwohls keinen Sinn macht, find ich irgendwie nicht recht nen gutes Argument
und wenn wer wirklich schreibt (x=y)=Z halt ich das fuer nen Denk oder tippfehler, wo der compiler ruhig maulen sollte ...
@GR_Watto
Siehe deinen anderen Thread ...
-
wer (x=y)=z schreibt, ist auch bereit mal ein const_cast zu schreiben. im übrigen könnte ein x=y=z denselben effekt haben, falls x bzw. y mal ein alias für y bzw. x ist. und dann hilft dir dein const nicht weiter. ich halte diese variante aber generell für wahrscheinlicher. im übrigen ist (x=y)=z ja nur undefiniert, falls x einen trivialen zuweisungsoperator hat (andernfalls befinden sich ja im operator bereits sequence points).
-
wer (x=y)=z schreibt, ist auch bereit mal ein const_cast zu schreiben
wer sowas absichtlich macht ... ja. wie gesagt, ich wuerd immer aufn schreibfehler tippen ...
Genau so wie jemand nen rueckabewert einer Zuweisung weiterverwenden sollte ... macht eigentlich kein sinn.
Das const bringt an der stelle nicht viel. macht aber auch nix kaputt.
Bei mir greift an der stelle eben nur die interne logic ...
soll der anwender meines operators auf den rueckgabewert schreiben koennen ?
noe ... in 99.99999999999999999 % der Faelle wertet er den gar nicht aus ...
wenn doch, und er gleich wieder drueberschreibt, isses logisch sehr zweifelhaft
also mach ma den mal const ... dann hats wenigstens die chance das beim "schreibfehler" der compiler mault.Nenn mir nen beispiel wo genau das const einer intuitiven Verwendung entgegen wirkt, dann werd ichs mir auch wieder abgewoehnen

Ciao ...
-
RHBaum schrieb:
Genau so wie jemand nen rueckabewert einer Zuweisung weiterverwenden sollte ... macht eigentlich kein sinn.
Also das kann ich nicht unterschreiben. Code wie dieser macht mir immer Bauchweh.
int sz_read = read(..); while ( 0 != sz_read ) { .... ..... // und am ende dann wieder sz_read = read(..); }Finde es einfach kürzer logischer besser und vor allem weniger Fehleranfällig
while ((sz_read = read(..)) != 0) { .... }Kurt
-
Also das kann ich nicht unterschreiben. Code wie dieser macht mir immer Bauchweh.
Ok hasst recht, ich berichtige:
Macht keinen Sinn, auf den Rueckabewert einer zuweisung zu schreiben ...
Ciao ...
-
RHBaum schrieb:
bei den anderen binaeren verkettenbaren operatoren hasst natuerlich vollkommen recht ...
Sofern es sich um Assignment Operatoren handelt, dann 'foo&', bei Non-Assignment 'const foo'.
RHBaum schrieb:
Nur weil es bei den Pods geht, soll es mit meinen Klassen auch gehen
Wer spricht denn von PODs? Obwohl es bei denen ja das Gleiche ist, wie mit primitiven Typen. Also ein weiteres Argument gegen 'const foo&'.
RHBaum schrieb:
obwohls keinen Sinn macht, find ich irgendwie nicht recht nen gutes Argument
Wieso macht es keinen Sinn? Hast du noch nie Code geschrieben, in dem Folgendes gemacht wurde?
b = a = 0;Nein? Dann kannst du dir vielleicht vorstellen, dass es Leute gibt, die sowas schon verwendet haben (mich eingeschlossen). Ändere nicht die Prinzipien einer Sprache, nur damit sie dir besser passt, und du damit andere mit deinem Erfahrungsschatz einschränkst.
RHBaum schrieb:
und wenn wer wirklich schreibt (x=y)=Z halt ich das fuer nen Denk oder tippfehler, wo der compiler ruhig maulen sollte ...
Nö. Der Compiler soll maulen, wenn's syntaktisch nicht korrket ist, und nicht wenn sich jemand vertippt oder 'nen Denkfehler hat. Niemand hat gesagt, dass C++ eine leichte Sprache ist. Und Fallen gibts überall. Ich denke da nur an
if (a = 0)Um solchen Sachen vorzubeugen, schreiben ja einige Leute die Konstante auf die linke Seite, also
if (0 = a)Aber was machst du, wenn du zwei l-values hast?
C++ ist nunmal keine idiotensichere Sprache, und das wird sie auch nie werden. Also versuche erst gar nicht, eine daraus zu machen.camper schrieb:
im übrigen ist (x=y)=z ja nur undefiniert, falls x einen trivialen zuweisungsoperator hat
Wieso das? Irgendwie steh ich im Moment auf'm Schlauch.
-
Wieso macht es keinen Sinn? Hast du noch nie Code geschrieben, in dem Folgendes gemacht wurde?
C/C++ Code:
b = a = 0;
C/C++ Code:Natuerlich verwende ich das auch ....
und das ist selbst mit dem const correct, weil es ja als
b = (a = 0) aufgeloest wird, und nicht als (b = a) = 0den ruckgabewert verwendest du schon, ich natuerlich manchmal auch, aber ich schreib nie darauf rum, das mein ich damit ...
Ich lass mich aber immer noch belehren:
nenn mir nen Fall, wo man auf die Rueckgabe einer Zuweisung rumschreibt, und es auch noch Sinn macht.Wer spricht denn von PODs? Obwohl es bei denen ja das Gleiche ist, wie mit primitiven Typen.
Vielleicht lieg ich da im Begriff falsch, aber bei PODs (plain old data) gehoerten bei mir die primitiven typen immer mit rein ... oder lieg ich da falsch ?
und da es fuer die nicht primitiven, aber doch PODs (struct union pointer) auch gilt, hab ichs halt auch so ausgedrueckt ...Ciao ...
-
RHBaum schrieb:
Natuerlich verwende ich das auch ....
und das ist selbst mit dem const correct, weil es ja als
b = (a = 0) aufgeloest wird, und nicht als (b = a) = 0Achso, da hab ich dich missverstanden. Dachte, du hättest was gegen 'x = y = z'. Dass '(x = y) = z' wenig Sinn macht, hatten wir ja schon geklärt.
RHBaum schrieb:
nenn mir nen Fall, wo man auf die Rueckgabe einer Zuweisung rumschreibt, und es auch noch Sinn macht.
Was Sinn macht oder nicht, ist natürlich relativ. Ich könnte mir aber Folgendes Szenario vorstellen:
void mach_irgendwas(foo& a) { //... } a = lese_irgendwas(); mach_irgendwas(a);Ich würde immer zu dieser Schreibweise tendieren, auch weil's einfach übersichtlicher ist. Wer dennoch eine etwas kompaktere Schreibweise bevorzugt, kann dies natürlich machen. Diese Freiheit bietet C++ nunmal.
mach_irgendwas(a = lese_irgendwas());Diese Möglichkeit würde mit const foo& als Rückgabe vom op= nicht mehr funktionieren.
RHBaum schrieb:
Vielleicht lieg ich da im Begriff falsch, aber bei PODs (plain old data) gehoerten bei mir die primitiven typen immer mit rein ... oder lieg ich da falsch ?
Laut Wiki nicht. Ich dachte eigentlich immer, dass PODs Strukturen sind, die keine selbstdefinierten Konstruktoren und Operatoren haben. Aber offensichtlich gehören die primitiven Typen auch dazu. Man lernt halt nie aus.
Naja, wie auch immer. Ich sprach allerdings nur von primitiven Typen. Dass Strukturen, die keinen selbstdefinierten op= haben und wiederum nur PODs als Member, sich genauso verhalten, sollte einen ja noch zusätzlich nachdenklich machen, dass man mit 'const foo&' bestehende Regeln bricht.
-
groovemaster schrieb:
camper schrieb:
im übrigen ist (x=y)=z ja nur undefiniert, falls x einen trivialen zuweisungsoperator hat
Wieso das? Irgendwie steh ich im Moment auf'm Schlauch.
das problem ist dorch, dass x zweimal zwischen zwei sequence points verändert wird, richtig?
ist nun zuweisungsoperator nicht trivial, handelt es sich um ganz normale funktionsaufrufe (nur mit operator schreibweise). alle seiteneffekte durch die initialisierung eines funktionsparameters müssen abgeschlossen sein, bevor die funktion selbst aufgerufen wird.
beispiel:
wir haben noch op<<= für streams überladen, so dass es sich wie op << verhält (beide geben ihren linken operanden weiter, so wie op= es tut).
dann wird niemand erwarten, dass(cout<<=a)<<=b;undefiniert ist. für builtins wäre es das aber.
-
Verstehe trotzdem noch nicht, was daran undefiniert sein soll. Der Compiler macht aus '(x = y) = z' im Grunde doch
x = y, x = zEgal, ob es sich um einen trivialen oder nicht-trivialen op= handelt, ist das doch definiert.

-
#include <iostream> int main() { int a, b = 1, c = 2; std::cout << ( ( a = b ) = c ) << std::endl; std::cout << a << std::endl; }in der ersten zeile wird auf jeden fall 2 ausgegeben. was in der 2. zeile steht, ist dagegen unbestimmt. der compiler darf hier machen, was er will.
-
Hast du zufällig eine Stelle im Standard parat, wo das beschrieben wird?
Ich dachte eigentlich, dass die Klammerung dafür sorgt, dass 'a = b' auf jeden Fall VOR 'a = c' durchgeführt wird. Sprich, dass am Ende a immer den Wert von c hat.
Oder was meinst du mit "der compiler darf hier machen, was er will"? Was könnte denn der Compiler hier theoretisch alles machen?
-
es scheint es genügt, dass x ein objekt oder ein enum ist, damit der ausdruck unproblematisch wird. Ich würde mich auf Kapitel 5 Abs.4 stützen:
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior vallue shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behaviour is undefined.*Example:
i = v[i++]; // the behaviour is unspecified
i = 7, i++, i++; // i becomes 9i = ++i + 1; // the behaviour is unspecified
i = i + 1; // the value of i is incrementd*nun ist unspecified zwar nicht dasselbe wie undefined - in der praxis kann man sich die unterscheidung aber im grunde sparen. des speichern des neuen wertes in einer variable ist nur ein seiteneffekt der zuweisung. in der regel wird man sicher entweder y oder z vorfinden. da das speichern aber nicht unbedingt atomisch erfolgt (insbesondere für grosse typen), könnte es auch etwas anderes sein.