absichtliches slicing bei swap-implementierung
-
hallo!
class foo { int a; public: void swap(foo&x) { std::swap(a,x.a); } }; class bar : public foo { int b; public: void swap(bar&x) { foo::swap(x); std::swap(b,x.b); } };ist in diesem code das absichtliche slicing in zeile 11 i.o.? slicing wird - so wie auch andere features aus C++ - immer schlecht dargestellt aber ich sehe gerade nicht, wieso es hier schlecht sein solle, geschweige denn, wie man das problem anders lösen könnte. jemand eine idee?
LG
-
schlangenmensch420 schrieb:
...ist in diesem code das absichtliche slicing in zeile 11 i.o.? slicing wird - so wie auch andere features aus C++ - immer schlecht dargestellt aber ich sehe gerade nicht, wieso es hier schlecht sein solle, geschweige denn, wie man das problem anders lösen könnte.
Na ja - rein optisch dreht es mir hier schon die Zehennägel hoch.
Formal ist das zwar korrekt, aber die erste Frage ist doch, wozu dieses konkrete
swaphier überhaupt gut sein soll. Einfach weglassen und im Falle eines Fallesstd::swapbenutzen wäre IMHO eine gute Alternative.
Der Code inbar::swapenthält zudem die implizite Annahme, dassbarvonfoogenauso abgeleitet ist. Bei einer Mini-Klasse mit drei Zeilen ist das kein Problem. Bei größeren Konstruktionen könnte man bei einer Änderung der Ableitungshierachie (z.B. Einfügen einer weiteren Basisklasse zwischenfooundbar) hier vergessen, dasswapanzupassen. Das kann dann zu übelsten Fehlern führen, die Du tagelang suchen darfst!Die Alternative ist ganz klar: weglassen! Und wenn
baroderfookomplizierter werden, so kümmere man sich zunächst um einen vernünftigen Move-Assignment-Operator. Dieser wird nämlich vonstd::swapaufgerufen.
Und wenn tatsächlich beide Klassen so kompliziert werden, dass bei beiden Klassen ein individuellesswapangebracht zu sein scheint, dann ist meines Erachtens das Klassendesign zu hinterfragen.Btw.: den foo::swap mit public Zugriff dürfte es gar nicht geben. Denn das kann ja auch jemand anders rufen, mit einem
foo*, der auf einbar-Objekt zeigt. Das sollte mindestens protected sein!Gruß
Werner
-
hallo werner!
danke für deine antwort. dein argument, dass änderungen in der klassenhierarchie dann einfluss auf das verhalten dieser methode haben, ist sehr valide und mir fiele spontan leider auch kein statischer schutzmechanismus ein, denn z.b.
std::is_base_ofgreift ja dennoch.bezüglich der alternative mit move-assign-operatoren: im echten projekt arbeite ich in einer hochgradig parallelen umgebung. beim moven muss ich mehrere mutexe (mutizen?) locken. wenn ich nun dreimal move, dann habe ich 3n locks. zudem kann ich dort die mutexe auch nicht effizient locken (wie es z.b.
std::locktäte), sondern muss sequenziell vorgehen. mit meinem swap brauche ich nun lediglich 2n locks, die ich auch alle gleichzeitig machen kann (i.d.r. schneller).die anmerkung wegen der sichtbarkeit ist gold wert, das habe ich tatsächlich vergessen! danke!
-
Solltest du dann nicht ein swapNoLock() machen, damit du bei derived::swap nicht insgesamt 2x locken musst (1x in derived::swap selbst und 1x in base::swap).