Kopierkonstruktor kurze Frage
-
Kurze Frage zum Kopierkonstrukotr... Den brauche ich nur wenn es sich um ein Objekt handelt, oder ? Also für einen "normalen" String wie in folgendem Beispiel sollte das so passen?
class test{ public: test(const std::string& name): my_name(name){}; const std::string& get_name(); private: const std::string my_name; }
Desweiteren noch die Frage, bringt es mir irgendeinen Vorteil bei get_name eine Referenz zurück zu geben ?
Sie jetzt so aus :const std::string& get_name(){ return this->my_name; }
-
Zur ersten Frage:
Nein, brauchst du nicht. Wenn du keinen Kopierkonstruktor anbietest, ihn aber auch nicht verbietest, dann generiert der Compiler bei Bedarf automatisch einen trivialen Kopierkonstruktor. Was da heisst, alle Datenmember werden stupide rüberkopiert.Hast du als member irgendwelche der Grunddatetypen (bool, int, double etc.) oder STL-Datentypen ist das kein Problem und es funktioniert alles wie es soll. Genauer gesagt, alle Member die kopierbar sind, funktionieren.
Ein Problem hast du bei Pointern, denn die werden auch "nur" kopiert, aber das worauf sie zeigen nicht (Shallow Copy). Und genau für solche Fälle musst du den Copy-Constructor selbst schreiben. Bei gutem Design betrifft das aber nur wenige Container Klassen gewöhnlich (wenn du z.B. eine eigene Datenstruktur implementierst) und selbst dann ist das meist immer noch gut kapselbar. Aber hier brauchst du die Regel der großen 3 (google mal).
Ein anderer Fall ist, wenn du einen std::unique_ptr als Member hast. Weil da musst du auch den pointee (also das worauf gezeigt wird) manuell kopieren, auch wenn das trivial geht:
struct Foo { int i; }; class Bar { std::unique_ptr<Foo> foo; public: Bar() : foo(std::make_unique<Foo>(5)) {} Bar(Bar const& other) : foo(std::make_unique<Foo>(*other.foo)) {} };
Der UniquePtr hebelt auch die Regel der großen 3 etwas aus.
Und noch als Anmerkung: Wenn du mit C++11 (oder jünger) unterwegs bist könnte man die Regel auch die Regel der großen 5 nennen.
-
Besten Dank für die ANtwort. Hab das noch gegoogelt, ist soweit klar.
Hast du noch was zur 2. Frage?
-
@Skym0sh0
Der Begriff "trivialer Copy-Ctor" ist mir neu. Würde wenn dann wohl auch nur für leere Klassen zutreffen, also welche die überhaupt keine Member haben. Denn "trivial" wird im Standard IIRC für "compilergeneriert und tut gar nix" verwendet.Also eine klasse hat z.B. nur dann einen trivialen Dtor, wenn alle ihre Basisklassen und Member einen trivialen Dtor haben, und sie den Dtor nicht selbst definiert.
@copyconstr
Eine Referenz zurückzugeben ist bei Objekten wie z.B. Strings schneller, da der String nicht kopiert werden muss (bzw. allgemein Objekten die halt teuer zu kopieren sind).
Dafür birgt es auch Gefahren. Denn wenn der Aufrufer den Getter verwendet um eine Referenz zu initialisieren, dann das Objekt zerstört, und dann über die Referenz den Wert auslesen möchte, dann kracht es (oder auch nicht, UB halt).EDIT: Klarstellung/Verbesserung
-
hustbaer schrieb:
@copyconstr
Eine Referenz zurückzugeben ist bei Objekten die Strings schneller, da der String nicht kopiert werden muss.
Dafür birgt es auch Gefahren. Denn wenn der Aufrufer den Getter verwendet um eine Referenz zu initialisieren, dann das Objekt zerstört, und dann über die Referenz den Wert auslesen möchte, dann kracht es (oder auch nicht, UB halt).Passiert das nicht auch dann, wenn ich den String als value zurückgebe, aber damit eine Referenz initialisiere?
PS Ich hab das mal getestet und habe den Eindruck, dass das temporäre Objekt, das bei der Rückgabe erstellt wird, lebt, bis die Referenz, die auf es verweist, untergeht. Demnach sind die Bedenken von hustbaer richtig!
-
copyconstr schrieb:
class test{ ... private: const std::string my_name; }
Wo wir schon bei vom Compiler generierten Methoden sind, noch eine kleine Anmerkung am Rande: Eine Member-Variable
const
zu deklarieren verhindert effektiv die Verwendung eines vom Compiler erzeugten Zuweisungsoperators.
z.B. isttest a, b; a = b;
damit nicht möglich, da bei dieser Operation die konstante Variable
my_name
auf den Wert vonb.my_name
gesetzt werden müsste.Das kann zwar so beabsichtigt sein, oft ist es jedoch so, dass zwar
my_name
konzeptionell unveränderlich ist, aber man dennoch eine Zuweisung in der o.g. Form zulassen will. In diesem Fall istmy_name
nicht wirklich konstant, und dieconst
-Qualifikation sollte weggelassen werden (dasprivate:
und die privaten Methoden die man selbst kontrolliert müssen dann sicherstellen, dassmy_name
nicht verändert wird)Finnegan
-
hustbaer schrieb:
@Skym0sh0
Der Begriff "trivialer Copy-Ctor" ist mir neu. Würde wenn dann wohl auch nur für leere Klassen zutreffen, also welche die überhaupt keine Member haben. Denn "trivial" wird im Standard IIRC für "compilergeneriert und tut gar nix" verwendet.Ein "trivialer Copy-Ctor" ist in etwa der von einem POD.
https://www.c-plusplus.net/forum/p2288364#2288364
-
hustbaer schrieb:
@Skym0sh0
Der Begriff "trivialer Copy-Ctor" ist mir neu. Würde wenn dann wohl auch nur für leere Klassen zutreffen, also welche die überhaupt keine Member haben. Denn "trivial" wird im Standard IIRC für "compilergeneriert und tut gar nix" verwendet.Okay, das meinte ich natürlich nicht. ich hab mir den Standard leider noch nicht als Bettlektüre hingelegt
Jetzt mal ohne Spass, ich hab den Ausdruck "trivial kopieren" nicht auf eine Definition bezogen gemeint, sondern ihn einfach so lapidar als Beschreibung gemeint. Quasi sprach ich unpräsize.
-
"Trivial kopierbar" ist gängig und sicher OK.
"Trivialer Kopierkonstruktor" ist zumindest mir nicht geläufig. Wenn camper's Beschreibung (Link von aufklärer) dem Wortlaut des Standards entspricht, dann ist aber auch dieser Begriff korrekt. Ich kannte den bloss nicht.