Operator= and CopyConstructor

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Operator= and CopyConstructor
Hi,

wann wird der AssignmentOperator und wann der CopyConstructor aufgerufen?
Ich hab in meiner Main zu A1 nämlich

Matrix<float> m3(3,3)
m3 = m1*m2

Und bekomme komische Fehler! Wird bei “m3 = …” automatisch auch der CC (zusätzlich zum AssignmentOperator!) aufgerufen?
(wenn ja, was macht das für einen Sinn?)

Thx :wink:


Du solltest am besten die Rule of Three beachten.


Wie meinst du das mit automatisch aufgerufen?
Also ich habe beim Assignment-Operator keine neue Matrix/Kopie erstellen müssen, in dem Fall verändert man ja die eigenen Werte und gibt *this zurück, ich denke nicht, dass sich irgendwas automatisch aufruft…
Vielleicht verstehe ich die Frage aber auch nicht ganz :slight_smile:


Der CopyConstructor wird immer dann aufgerufen, wenn du ein Objekt (keine Referenz!) in einer Methode zurueck gibst, oder beim Anlegen eines Objektes mittels eines anderen.
Der Assignment operator= wird dagegen immer bei Variablenzuweisung aufgerufen.

Beispiel:
Matrix m3(3,3);
m3 = m1*m2;

operator* → copy → operator= → copy

Allerdings:
Matrix m3 = m1 * m2;

operator* → copy

Wenn du dir unsicher bist, ist es immer hilfreich dir in den jeweiligen Operatoren Debugoutputs zu generieren.


thx soweit schon mal…

muss ich dann im Copyconstruktor überhaupt noch den operator= aufrufen?
(hab ich nämlich gemacht, um das Array zu kopieren)


Ich weiss leider nicht genau wie du jetzt den operator= aufrufst. Aber einfach nur den Array Pointer kopieren ala:
T* data = other.data;
reicht nicht aus!

Du musst die Daten schon explizit kopieren.


[quote=Michi D.]muss ich dann im Copyconstruktor überhaupt noch den operator= aufrufen?
(hab ich nämlich gemacht, um das Array zu kopieren)
[/quote]

Müssen sicherlich nicht, ich habs ohne, man bekommt ja eine Matrix von der man die ganzen Werte in sich selber einfügt und mit Hilfe von _data = new T[…] hole ich Speicherplatz in welchen ich die Werte eintrage.


ja, c++ macht ganz böse sachen, wenn man das bei eigenen/allokierten datentypen nicht beachtet :wink:


Müssen sicherlich nicht, ich habs ohne, man bekommt ja eine Matrix von der man die ganzen Werte in sich selber einfügt und mit Hilfe von _data = new T[…] hole ich Speicherplatz in welchen ich die Werte eintrage.
[/quote]
Wenn ich das richtig verstehe, hast Du da ein Speicherleck.
Im operator=() sollte der Speicher für die Matrix (*this Objekt) schon reserviert sein, sonst würde man ja mit set/getEntry() ein undefiniertes Verhalten bekommen (von lazy allocation/copy gehe ich jetzt mal nicht aus). Im operator=() muß man also nur die Daten von other nach *this kopieren und ggfs. vorher schauen ob die Dimensionen passen. Nicht vergessen, dass man auch sowas machen darf:

Matrix m(4,4);
m = m;

Schaut blöd aus, passiert aber impliziert öfter als man denkt…


Nicht zwangslaeufig… Ihr muesst auch aufpassen, es geht auch sowas wie

Matrix m1(3,3);
Matrix m2(4,4);
m1 = m2;

Allerdings muesst ihr wegen Speicherlecks hier auch aufpassen!


Also bei mir geht es nicht… :wink: bzw. es ist ein Fehler und wird auch so behandelt. Muß das funktionieren oder reicht es, wenn man die Problematik erkannt hat? :slight_smile:


Es muss schon funktionieren :wink:

Also wenn die Dimensionen nicht stimmen musst du neu anlegen / loeschen etc…


Davon steht aber NICHTS in der Aufgabenstellung, genauso wenig wie zu memcpy/std::cpy, zumindest als Hinweis sollte das in der Aufgabenstellung drinstehen… Vielleicht will der User dass m1 eine 3x3 Matrix ist und weist ihr aus Versehen eine 4x4 Matrix zu, dann hätte man ja genauso gut eine Fehlermeldung bringen und die Operation verweigern können… Bitte um klarere Aufgabenstellungen, was gehen und was nicht gehen sollte und wo man vielleicht das Programm beenden sollte. API/Manual-Hinweise (SP-Like) wären super :slight_smile:


Also ich schmeiß da eine Exception und ich finde dieses Verhalten sinnvoller. Spezifiziert ist es nicht.

Viel Spaß beim Debuggen, wenn inkompatible Matrizen einfach so zugewiesen werden können.


zu memcpy/std::cpy steht nichts dazu, weil es in diesem Fall auch nicht die ideale Loesung ist!
Besser hingegen ist eine for Schleife die ueber die einzelnen Elemente iteriert. Dann wird naemlich immer der operator= der einzelnen Elemente aufgerufen. Angenommen das Template waere eine Klasse die Pointer als Member enthaelt. Dann wuerde mit memcopy/std::copy lediglich die Pointeradresse kopiert werden, die eigentlich Daten aber nicht.

Ansonsten braucht man ohnehin keine API oder Manpages waruf ein Hinweis sinnvoll ist… (korrigiert mich wenn ich mich jetzt taeusche)


Du hast Recht, aber dann ist der operator* wahrscheinlich auch nicht definiert… Also ich bleibe bei PODs. Walks like a matrix, swims like a matrix, … it’s a matrix! :smiley:
Ideal ist hier ja wohl schnell… warum sonst C++…


also des würd mich etz scho mal interessieren was dann die ideale Lösung ist. Ist ja nur ne Sache von Block A auskommentieren, Block B wieder rein. hab aber keine Lust deswegen Punkte abgezogen zu bekommen.

könntet ihr sowas bitte spezifizieren in zukunft? weil für mich macht beides sinn: neu anlegen oder exception werfen.


Ich glaub das ist so nicht ganz richtig.
std::copy ist ein template und ruft daher den operator= auf.
Von daher laeuft alles ordnungsgemaesz…

Vermutlich optimiert „schleife mit get/set-Entry“ und std::copy zum gleichen Ergebnis :wink:
getEntry und std::copy sind quasi inline, weil sie nicht seperat kompiliert werden.
Falls der Templateparameter POD ist, ist es vielleicht auch aequivalent zur memcpy-Variante.
(aber wozu die Einschraenkung auf PODs, wenn es std::copy gibt)

Ich finde Neuanlegen auch sinnvoll, da sich der std::vector analog verhaelt.
(andererseits puffert der vector auch und hat ne resize-methode ^^)


Au, nice, daran hatte ich noch garnicht gedacht. In SP lernt man halt einfach wie man sauberen Code schreibt (memcpy)… :-p

ACK. memcpy raus…

Der Vergleich hinkt: std::vector ist kein Vektor im mathematischen Sinne und hat auch keinen operator* (AFAIK?). Wenn ich mit Matrizen im mathematischen Sinne hantiere, dann sollte ich doch wissen wie groß die Matrix ist, die ich gerade zuweise. Bei der Multiplikation müssen die Matrizen ja auch zusammenpassen, warum sollte es bei der Zuweisung dann anders sein? Finde ich inkonsistent.

EDIT: Überhaupt: wenn schon templates, dann sollten die Dimensionen der Matrix auch template parameter sein. Type safety…