Smartpointer Problem



  • Hi,

    ich befasse mich seit Kurzem mit Smartpointern, genauer gesagt mit std::unique_ptr.

    Mein Frage:

    Ich möchte einen unique_ptr an eine andere Klasse übergeben, wo er dann in einen std::vector gespeichert wird. Ist das irgendwie möglich, oder muss ich da shared_ptr verwenden?

    Gruß



  • Raven280438 schrieb:

    Hi,

    ich befasse mich seit Kurzem mit Smartpointern, genauer gesagt mit std::unique_ptr.

    Mein Fragen:

    1.)
    Ist es irgendwie möglich einen unique_ptr nicht in der Initialisierungsliste der Klasse zu initialisieren, sondern erst später in einer anderen Methode?

    2.)
    Ich möchte einen unique_ptr an eine andere Klasse übergeben, wo er dann in einen std::vector gespeichert wird. Ist das irgendwie möglich, oder muss ich da shared_ptr verwenden?

    Gruß

    1. Ja, das ist möglich. Entweder einfach einen neuen std::unique_ptr<..> zuweisen oder mit std::unqiue_ptr<..>::reset(..)
    2. Ja, das ist möglich mit dem std::unique_ptr<..>, allerdings wird dann gemoved, ev. nicht das was du möchtest. std::shared_ptr benötigst du nur dann, wenn du geteilten Besitz hast - in den allermeisten Fällen ist das nicht der Fall.



  • Raven280438 schrieb:

    Ich möchte einen unique_ptr an eine andere Klasse übergeben, wo er dann in einen std::vector gespeichert wird. Ist das irgendwie möglich, oder muss ich da shared_ptr verwenden?

    Warum benutzt du einen unique_ptr?
    Warum willst du ihn übergeben?
    Bist du sicher, dass du an dieser Stelle nicht einen "normalen" Pointer oder eine Referenz willst?

    Überall nur noch Smartpointer zu verwenden ist eine dumme Idee. Ihre Aufgabe ist es, ein Objekt solange am Leben zu erhalten, bis es nicht mehr benötigt wird und es danach wirklich zu löschen. Sie sollen Pointer und Referenzen nicht vollständig ersetzen.



  • Hi,

    zum konkreten Problem:
    Ich bastel grad ein bisschen mit DirectX11 und habe da einen Gamestate-Manager.
    Diesem kann man ein Gamestate hinzufügen und er speichert sie in einem Vector.
    Der Vector soll dann unique_ptr enthalten, damit sie beim Beenden wieder gelöscht werden.

    Wie gehe ich das am Besten an? Soll ich der AddGamestate()-Methode einen normalen Zeiger übergeben, in einen unique_ptr umwandeln und dann im Vector speichern, oder kann ich auch direkt einen unique_ptr übergeben?

    Gruß



  • Warum enthält der Vektor überhaupt Pointer auf Gamestate und nicht Gamestate - Objekte?



  • Warum fügt man dem GameState-Manager GameStates hinzu? Warum erzeugt er diese nicht selber?



  • Hi,

    mein Gamestate-Klasse ist Abstrakt.
    Die richigen Gamestates werden von dieser Klasse abgeleitet.

    Die Gamestates sind nicht Teil meiner "Engine" sondern werden im Programm selber erzeugt, damit man mit ihnen Arbeiten kann.

    Wenn man jetzt zB 2 verschiedene Spiele mit der gleichen Engine hat, kann der GamestateManager doch garnicht alle möglichen Gamestates kennen (um sie erzeugen zu können). Die kennt doch nur das jeweilige Programm, oder?

    Gruß



  • Für mich hört sich das Konzept merkwürdig an. Aber ohne Details zu kennen (die ich eigentlich auch gar nicht kennen will) kann man wenig dazu sagen.
    Möglicherweise wäre das Problem mit Templates zu lösen.



  • Hi,

    vielleicht hab ich den Sinn von GameStates auch nicht verstanden 😉

    Für mich ist zB das Start-Menu ein Gamestate.
    Wenn ich aber 2 verschiedene Spiele mit der gleichen Engine programmiere, sind die Menus doch völlig unterschiedlich zueinander.
    Deshalb kann der Manager die ja auch nicht kennen.

    Ich wollte dann im eigendlichen Spiel einfach eine Klasse von meinem Abstrakten Gamestate ableiten und an den Manager schicken.
    Wenn das Spiel dann beendet wird, sollen auch alle Gamestates gelöscht werden (deshalb dachte ich an unique_ptr im GameStateManager).

    Gruß



  • Also zu dem ganzen Gamestate-Ansatz sage ich mal nichts, mach da ruhig einfach mal weiter, wenn's dann am Ende nicht perfekt ist hast du ja zumindest was gelernt. Und hey, irgendwie wird es schon funktionieren. Wegen dem unique_ptr: std::move ist dein Freund!

    #include <vector>
    #include <memory>
    
    class game_state
    {};
    
    class game_state_manager // Damn a manager class :(
    {
    	std::vector<std::unique_ptr<game_state>> game_states_;
    
    public:
    	game_state* add_state(std::unique_ptr<game_state> state)
    	{
    		game_states_.push_back(std::move(state));
    		return game_states_.back().get();
    	}
    };
    
    int main()
    {
    	game_state_manager gsm;
    	auto state = std::make_unique<game_state>();
    	auto state_ptr = gsm.add_state(std::move(state));
    }
    

    So in etwas wolltest du das, oder? Alles verstaendlich? RValue-References und std::move solltest du dir vermutlich noch mal angucken. 😉



  • Hi,

    danke für den Code.

    Was gibts denn für Alternativen zu Gamestates? Ich will natürlich weiter dazulernen 😉

    Gruß



  • Gamestates ueber abstrakte Klassen verteilen sieht mir sehr nach overengeneering aus, denn ueblicherweise ist das eine einfache FSM.
    Meistens hat man ein enum fuer die ganzen Zustaende, die GameState-Klasse empfaengt events und ruft dann ueber ein switch die richtige Funktion auf. Das ist sehr viel konkreter und Funktionalitaet laesst sich leichter ergaenzen.



  • Hi,

    werden bei unique_ptr irgendwie bei der Initialisierung schon Objekte angelegt und wieder gelöscht?
    Ich habe das Problem, dass bei der Initialisierung Destruktoren von Objekten aufgerufen werden, die eigendlich noch garnicht existieren dürften.
    Diese Objekte sind nicht richtig initialisiert (vielleicht weil sie keinen Default-Konstruktor habe), deshalb gibts beim Löschen wieder Probleme.

    Gruß



  • Raven280438 schrieb:

    werden bei unique_ptr irgendwie bei der Initialisierung schon Objekte angelegt und wieder gelöscht?

    Hängt davon ab, ohne deinen Code zu sehen, kann man das nicht sagen...



  • Raven280438 schrieb:

    werden bei unique_ptr irgendwie bei der Initialisierung schon Objekte angelegt und wieder gelöscht?

    Nicht die Typen, auf die der Zeiger zeigt. Intern werden natürlich schon Objekte erzeugt.



  • manni66 schrieb:

    Intern werden natürlich schon Objekte erzeugt.

    Ist das so 'natürlich'? Was soll denn da erzeugt werden?



  • Jockelx schrieb:

    manni66 schrieb:

    Intern werden natürlich schon Objekte erzeugt.

    Ist das so 'natürlich'? Was soll denn da erzeugt werden?

    Der unique_ptr selber?



  • Jockelx schrieb:

    manni66 schrieb:

    Intern werden natürlich schon Objekte erzeugt.

    Ist das so 'natürlich'? Was soll denn da erzeugt werden?

    beispielsweise der Deleter... 😉



  • Mmh, ok, hab irgendwie aus dem 'no-size-overhead' geschlossen, dass da nichts erzeugt wird.
    Aber auch ein leerer Deleter muss ja erzeugt werden.



  • Hi,

    im Detail:

    Ich habe 2 Klassen:

    class Primitives::Triangle : public IRenderable
    {
    [...]
    ];
    
    class TestApp::TestState
    {
    private:
    std::unique_ptr<Primitives::Triangle> Triangle;
    [...]
    };
    

    Im Konstruktor der TestState-Klasse wird das Triangle erzeugt:

    this->Triangle = std::unique_ptr<Primitives::Triangle>(new Primitives::Triangle(glm::vec3(50, 100, 0), glm::vec3(100, 50, 0), glm::vec3(150, 100, 0)));
    

    Durch Breakpoints hab ich rausgefunden, es wird zuerst der Kontruktor der Triangle-Klasse aufgerufen, dann sofort wieder der Destruktor.
    Beim Beenden des Programms wird dann nochmal der Destruktor der Triangle-Klasse aufgerufen, was zu Problemen führt.

    Liegt das an dem unique_ptr, oder hab ich irgendwo anders im Programm einen Fehler?

    Gruß


Anmelden zum Antworten