Wann sollte man Kopieren/Zuweisung verbieten?



  • Hi,

    wann sollte man Copy-Konstruktor und Zuweisungsoperator private machen, sprich das Kopieren und Zuweisen verbieten?

    Gibt es da irgendwelche Regeln für?



  • Wenn die Klasse einen Pointer managed, der auf einen dynamisch allokierten Speicherbereich zeigt und man zu faul ist, zusätzlich Reference Counting oder ähnliche Techniken zu implementieren.



  • Shlo schrieb:

    Wenn die Klasse einen Pointer managed, der auf einen dynamisch allokierten Speicherbereich zeigt und man zu faul ist, zusätzlich Reference Counting oder ähnliche Techniken zu implementieren.

    Nein! Faulheit darf nie ein Grund sein. Denn dann kann man es ja immernoch in einen boost::shared_ptr packen.

    Es macht dann sinn, wenn ein kopieren nicht sinnvoll ist - zB bei Dateien, ein Stream Objekt zu kopieren macht nicht viel Sinn.

    Oder zB einen singleton sollte man auch nicht kopieren.



  • Faulheit darf nie ein Grund sein

    wenigstens kein offizieller 😉

    Zuweisung private ist IMO auch bei Interface-Klassen/abstrakten Basis-Klassen sinnvoll und generell bei Klassen die tpyischerweise eher über Zeiger gehandelt werden, als "direkt" über das Objekt



  • Hallo,
    grob gesagt macht das Kopieren nur für value-types sinn. Reference-Typs hingegen sollten nicht kopiert werden (
    Den Unterschied zwischen value-types und reference-types findet man z.B. im Stroustrup Abschnitt 4 erklärt. Kurz: Erstere werden durch ihren Wert bestimmt. Kopieren macht hier viel sinn. Letztere werden durch ihre Identität bestimmt. Kopieren ist daher eher sinnlos).



  • Ich mache das in zwei Fällen (eigentlich nicht einmal direkt, dafür gibt es boost::noncopyable):

    - Basisklassen für eine Klassenhierarchie bekommen ein boost::noncopyable als Basisklasse. Polymorphie und Wertsemantiken (also Zuweisung) beißen sich, und damit ist das Thema für den Rest der Hierarchie geklärt.
    - Wenn es mal low-leveler wird und man eine Wächterklasse braucht, die im Destruktor z.B. DeleteDC aufruft, oder allgemein Wrapperklassen für C-API-Resourcen bekommen ebenfalls ein boost::noncopyable als Basisklasse, wenn es von der Art der Resourcen her nicht anders geht. Ein HWND-Wrapper ist z.B. prinzipiell nicht kopierbar.

    Bei allen anderen Klassen sollte sich das Kopierverhalten IMHO allein aus den enthaltenen Datenelement ergeben. Was nicht kopiert werden kann, wird nicht über einen T*, sondern einen boost::scoped_ptr<T> in der Klasse gehalten - und damit ist sie automatisch nicht kopierbar.



  • shadow* schrieb:

    wann sollte man Copy-Konstruktor und Zuweisungsoperator private machen, sprich das Kopieren und Zuweisen verbieten?

    immer. und wenn du dann mal siehst, daß ne klasse kopiert werden sollte, baueste halte die beiden funktionen bzw läßt die default-funktionen zu. aber erstmal verbietest du es am besten immer.



  • Seh ich auch so, allerdings spar ich mir das Kopierverbot, wenn der compilergenerierte Kopierkonstruktor schon das richtige tut. Dann geht nichts kaputt, wenn jemand eine Kopie macht ... ob sie ihm was nützt, muss er/sie schon selbst entscheiden.



  • Bashar schrieb:

    Seh ich auch so, allerdings spar ich mir das Kopierverbot, wenn der compilergenerierte Kopierkonstruktor schon das richtige tut. Dann geht nichts kaputt, wenn jemand eine Kopie macht ... ob sie ihm was nützt, muss er/sie schon selbst entscheiden.

    es verhindert manchmal fehler. in ne ganz gut laufende klasse kann mir doch allzu leicht passieren, daß ich man ein HANDLE (aus <windows.h>, könnte aber auch von jedem anderen bs kommen) auf ne nicht-kopierbare ressource reinschmiere.
    typischerweise haben aber klassen, bei denen sowas passieren könnte, zwei fein zusammen auftretende eigenschaften:
    - sie sind von vorn herein inhaltlich nicht für's kopieren geeignet, bzw die bedeutung des kopieren ist unklar.
    - sie sind teuer zu kopieren, weshalb ich sie eh nur mit referenzen oder zeigern anfassen will.
    also schmiere ich in jede klasse zuerstmal mein makro "NOCOPY" und gut ist's. mit dem msvc60 hat die von mir eingestellte ide das sogar übernommen.
    jetzt mit mingw-studio hab ich noch andere sorgen.



  • Das wär dann ja so ein Beispiel, wo der compilergenerierte Kopierkonstruktor nicht das richtige tut.



  • Also Klassen die ein Handle als Membervariablen haben auf jeden Fall die Kopie verbieten? 😕



  • volkard schrieb:

    in ne ganz gut laufende klasse kann mir doch allzu leicht passieren, daß ich man ein HANDLE (aus <windows.h>, könnte aber auch von jedem anderen bs kommen) auf ne nicht-kopierbare ressource reinschmiere.

    Wenn die Resource freigegeben werden soll, warum ist sie nicht in einer RAII-Klasse? Wenn sie nicht freigegeben, sondern nur beobachtet werden soll, kann das Handle ja kopiert werden.

    Vielleicht lebe ich nur in einer zu idealen Welt, dass ich in 95% der Fälle den generierten Kopierkonstruktor ruhigen Gewissens übernehmen kann 🙂



  • eichamt schrieb:

    Also Klassen die ein Handle als Membervariablen haben auf jeden Fall die Kopie verbieten? 😕

    sofern sich das handle nicht vernünftigt kopieren lässt: Ja



  • operator void schrieb:

    Wenn die Resource freigegeben werden soll, warum ist sie nicht in einer RAII-Klasse?

    weil die apis populärer betriebssysteme für c gemacht sind. nicht um alles gibt es schon c++-wrapper.

    Wenn sie nicht freigegeben, sondern nur beobachtet werden soll, kann das Handle ja kopiert werden.

    ich will aber nicht erlauben, was vermutlich vielleicht geht, sondern ich will nur erlauben, was sinnvoll ist.
    wenn sie nur beobachtet werden soll, ist kopieren wohl kaum die sinnvolle verfahrensweise dazu. nur beobachten von klassen-instanzen heißt für mich: sich nen zeiger holen und öfters mal das objekt angucken, wo der zeiger hinzeigt. nicht ne kopie machen und die öfters mal angucken.

    Vielleicht lebe ich nur in einer zu idealen Welt, dass ich in 95% der Fälle den generierten Kopierkonstruktor ruhigen Gewissens übernehmen kann 🙂

    och, die kann ich auch ruhigen gewissens übernehmen. aber ich verbiete das kopieren trotzdem. vielleicht, weil ich kopieren an sich nicht gerne mag, dieses generell exceptiongefähliche und langsame spiel.



  • volkard schrieb:

    weil die apis populärer betriebssysteme für c gemacht sind. nicht um alles gibt es schon c++-wrapper.

    Für Sachen wie Windows' Handletypen kann man sich doch aber schon mal eine eigene Klasse gönnen. Sonst muss man ja Destruktoren schreiben und kriegt mit der Exceptionsicherheit arge Probleme.

    volkard schrieb:

    wenn sie nur beobachtet werden soll, ist kopieren wohl kaum die sinnvolle verfahrensweise dazu. nur beobachten von klassen-instanzen heißt für mich: sich nen zeiger holen und öfters mal das objekt angucken, wo der zeiger hinzeigt. nicht ne kopie machen und die öfters mal angucken.

    Ich dachte an das Beobachten von Objekten über ein Handle. Das wäre in meiner perfekten Welt (;)) dann auch das einzige, wofür man ein rohes Handle oder einen rohen Zeiger als Element einer Klasse verwendet. Alles andere kommt in ein Wrapperobjekt.


Anmelden zum Antworten