Dependency injection



  • Habe eine Klasse die als member eine Referenz auf eine andere Klasse hält.

    • Wie ist es jetzt (ohne hässliches placement new) möglich hier die special member functions zu implementieren?
    • ich hatte mal irgendwo gelesen, dass es in einer Vererbungshierarchie typischerweise nicht üblich ist, Objekte zu moven bzw. zu kopieren, wieso ist das so? Wegen dynamic binding?


  • Ich versteh nicht so wirklich, was du willst.



  • struct A{};
    struct B{
      B(A const & a) : a_{a}
    
    const A& a_;
    };
    

    hier sind ja der default ctor und assignment operator implizit deleted.

    wie behilft man sich in so einem Fall oder realisiert man die special member function für gewöhnlich nicht, wenn man in einer Klasse eine referenz auf die Instanz einer anderen Klasse hält?



  • @sewing sagte in Dependency injection:

    realisiert man die special member function für gewöhnlich nicht, wenn man in einer Klasse eine referenz auf die Instanz einer anderen Klasse hält?

    Assignment geht ja dann schlecht ...



  • das meine ich ja, also nimmt man das einfach hin dann?



  • @sewing Ist ja nicht zu ändern!?



  • ist das halten einer Referenz in dieser Form denn als schlechter Stil im Allgemeinen zu vermeiden?



  • Naja du hast keine große Auswahl. Ich behelfe mir dann meist mit nem smartpointer, auch wenn das unschön ist. Ich bevorzuge die Referenzen, aber wenn man das Objekt eben kopieren will, muss man sich halt anderweitig behelfen.



  • @it0101 sagte in Dependency injection:

    Ich behelfe mir dann meist mit nem smartpointer

    Warum?
    Smartpointer sagt doch dass genaue Gegenteil von Referenz ("gehört mir komplett/ein bisschen" versus "gehört mir überhaupt nicht").



  • @jockelx sagte in Dependency injection:

    "gehört mir überhaupt nicht"

    ist wohl eher ein "gehört mir zwar überhaupt nicht, aber sieh gefälligst zu, daß es gültig bleibt!".



  • Ja, und das heisst?
    Immer und überall shared_ptr, weil man zu sehen muss, dass es gültig bleibt?
    Nee, danke.



  • Was spricht gegen eine Kopie (außer höherer Speicherverbrauch)?



  • Allgemein sicherlich überhaupt nichts.
    Allerdings wissen wir ja nicht, was der TE mit seinem

    const A& a_;
    

    bezwecken will. Und da jetzt shared_ptr als Alternative vorzuschlagen, fand ich sehr komisch/unpassend.



  • @swordfish sagte in Dependency injection:

    Was spricht gegen eine Kopie (außer höherer Speicherverbrauch)?

    Bei einer Kopie hast du das Problem, dass du die Änderungen im "Hauptobjekt" nicht mitbekommst.
    Wenn das Objekt konstant ist, nehm ich auch die Kopie, aber wenn du eine Const-Referenz einsetzt, dann gehts dir ja in aller Regel darum, dass du Zugriff auf Informationen dieses Objekts hast, auch wenn es sich ändert. Da hilft dir eine Kopie natürlich nicht.

    Der Smartpointer ( in meinem Fall meist std::shared_ptr<T> ) hat halt den bereits erwähnten Vorteil, dass er gültig bleibt, genau wie die Referenz. Sonst könnte man auch einen normalen Pointer nehmen, aber da greift man immer ins Ungewisse weil sich die Gültigkeit nicht prüfen lässt.

    @Jockelx :
    was wäre denn deine bevorzugte Lösung, wenn man ein Objekt referenzieren will, was sich ändert, d.h. wo die Kopie nicht infrage kommt?
    Vielleicht gefällt mir die ja besser als die shared_ptr-Variante. Ich habe das Problem zwar selten, aber so richtig zufrieden bin ich da mit meiner shared_ptr-Variante nicht.



  • @it0101 sagte in Dependency injection:

    Der Smartpointer ( in meinem Fall meist std::shared_ptr<T> ) hat halt den bereits erwähnten Vorteil, dass er gültig bleibt, genau wie die Referenz. Sonst könnte man auch einen normalen Pointer nehmen, aber da greift man immer ins Ungewisse weil sich die Gültigkeit nicht prüfen lässt.

    Ich nehme da den normalen Pointer.
    Die 'Gültigkeit' mit smartpointern ist ja ein Trugschluss, nur weil es nicht 'knallt', wenn du ein Objekt nutzt, was es eigentlich nicht mehr geben dürfte.
    Dadurch wird es ja nicht richtig, vielleicht sogar nur schwerer zu erkennen.



  • @jockelx sagte in Dependency injection:

    Die 'Gültigkeit' mit smartpointern ist ja ein Trugschluss, nur weil es nicht 'knallt', wenn du ein Objekt nutzt, was es eigentlich nicht mehr geben dürfte.

    Warum ist das ein Trugschluss? Wenn man mit den Smartpointern so umgeht wie das vorgesehen ist
    ( also nicht Sachen wie "delete myptr.get();" macht ), dann sollte das eigentlich passen. Im Allgemeinen habe ich den Eindruck, dass die Anwendung von Smartpointern Software sogar weniger fehleranfällig gemacht hat und auch die Anfälligkeit für Memoryleaks reduziert.



  • @jockelx sagte in Dependency injection:

    Die 'Gültigkeit' mit smartpointern ist ja ein Trugschluss, nur weil es nicht 'knallt', wenn du ein Objekt nutzt, was es eigentlich nicht mehr geben dürfte.

    Wann kann man denn durch einen Smart Pointer ein Objekt nutzen, das es eigentlich nicht mehr geben dürfte? Und warum dürfte es dieses Objekt wann nicht mehr geben?



  • @it0101
    Semantisch ist dein Programm dann doch immer noch falsch, das meinte ich mit Trugschluss.
    Blöd sowas allgemein/abstrakt zu diskutieren; ich hab z.B. in meinem Kopf den Fall, dass die Klasse nur SINNVOLL arbeiten kann, wenn das Referenz/Pointer Objekt auch wirklich länger lebt, als die Klasse selber.
    Wenn du was anderes im Kopf hast, dann ist ein smart_ptr viellciht auch gut.

    @swordfish
    Siehe oben. Von der Programmlogik dürfte es das Objekt nicht mehr geben. Sonst wäre der normale Pointer auch noch gültig.



  • @jockelx sagte in Dependency injection:

    @it0101
    dass die Klasse nur SINNVOLL arbeiten kann, wenn das Referenz/Pointer Objekt auch wirklich länger lebt, als die Klasse selber.

    Und genau das stellst du ja mit dem shared_ptr sicher. Das referenzierte Objekt ( im shared_ptr ) lebt mindestens solange wie die Instanz deiner Klasse.

    Genau deswegen sind bei mir Smartpointer im Allgemeinen der Notnagel für fast alles, wo Kopien und Referenzen an ihre Grenzen stoßen 😎
    "Normale Pointer" verwende ich eigentlich nur im Bereich Buffer lesen/schreiben.
    Würdest du in meinem aktuellen Projekt nach den Keywords "new" oder "delete" suchen, würdest du herb enttäuscht werden :face_with_stuck-out_tongue:



  • @it0101
    Ja, das ist doch klar, aber das ist halt gerne auch mal Mist.

    class Window
    {..}
    
    class Button(Window* parent)...
    
    

    Mein Button darf nicht länger leben, als mein Window.
    Wenn mein Window zerstört wird, dann soll bitte kein Child leben und denken, es könnte noch irgendwas sinnvolles mit dem Window anfangen.
    Das ist falsch programmiert und das will ich dann nicht durch einen smart_ptr vertuschen, indem das Programm nicht knallt, sondern irgendwas unsinniges mit dem nicht mehr existierendem Fenster macht.