Pointer class soll sich selbstständig löschen.



  • Hallo, ich erzeuge per linke Maustaste mit new ein Objekt einer Klasse, diese soll sich nach erledigen ihrer Aufgabe von selbst wieder löschen.

    if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
        {
            sf::Vector2f temp;
            temp.x = sf::Mouse::getPosition(window).x;
            temp.y = sf::Mouse::getPosition(window).y;
    
            _PAR = new PARTICLE(3000,10,6,"Images/Sprite.png", temp);
        }
    
        if(_PAR->_LifeOver())
        {
            _PAR->~PARTICLE();
        }
    

    Natürlich funktioniert es so nicht ^^, leider habe ich noch riesen Probleme mit Zeiger, aber ich arbeite daran.



  • Zu jedem new gehört ein delete, also

    delete par; // _PAR (s. P.S.)
    

    P.S. Namen mit Unterstrich und Großbuchstaben am Anfang sind reserviert für die Compilerhersteller.



  • 1. Löschen erfolgt mit delete , vom "normalen" Benutzer muss der Destruktor nie direkt aufgerufen werden.
    Hier die korrigierte Fassung:

    // ...
    if(_PAR->_LifeOver())
    {
        delete _PAR;
    }
    

    2. Der gezeigte Code verlangt a.) keine Member-Variable und b.) kein mit new erzeugtes Objekt. D.h. Du könntest eine automatische Variable verwenden:

    // ...
    PARTICLE PAR(3000,10,6,"Images/Sprite.png", temp);
    

    Diese wird automatisch wieder zerstört, sobald der Scope endet. Ev. verlangt aber nicht gezeigter Code, a. und b.



  • [quote="Th69"]Zu jedem new gehört ein delete/quote] Zu jedem new gehört ein Smart-Pointer. :p



  • 1. Löschen erfolgt mit delete, vom "normalen" Benutzer muss der Destruktor nie direkt aufgerufen werden.
    Hier die korrigierte Fassung:
    C++:
    // ...
    if(_PAR->_LifeOver())
    {
    delete _PAR;
    }

    Funktioniert nicht, bin aber sicher ich Schuld. Hier nochmal der gesamte Code, sind nur paar Zeilen:

    #include <iostream>
    #include <SFML/Graphics.hpp>
    
    #include "Particle.hpp"
    
    using namespace std;
    
    sf::RenderWindow window;
    sf::RenderTexture _RenderTexture;
    
    sf::Event event;
    sf::Mouse _Mouse;
    sf::Sprite _Image;
    
    void Par(sf::RenderTexture &render);
    
    PARTICLE *_PAR = new  PARTICLE(100,10,6,"Images/Sprite.png", sf::Vector2f(100, 100));
    
    int main()
    {
    
        window.create(sf::VideoMode(1280, 800 ,32), "Mengo", sf::Style::Default);
    	window.setKeyRepeatEnabled(true);
    	window.setFramerateLimit(30);
    
    	_RenderTexture.create(1280,800, true);
    	_RenderTexture.setSmooth(true);
    
        _Image.setTexture(_RenderTexture.getTexture());
    
    	while(window.isOpen())
    	{
            while(window.pollEvent(event))
    		{
    			switch(event.type)
    			{
    			case sf::Event::Closed:
    				window.close();
    
    			default: break;
                }
    		}
    
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
            window.close();
    
        window.clear(sf::Color(sf::Color::Black));
    
        Par(_RenderTexture);
    
        _RenderTexture.display();
    
        window.draw(_Image);
    
        window.display();
    	}
        return 0;
    }
    
    void Par(sf::RenderTexture &render)
    {
        if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
        {
            sf::Vector2f temp;
            temp.x = sf::Mouse::getPosition(window).x;
            temp.y = sf::Mouse::getPosition(window).y;
    
            _PAR = new PARTICLE(3000,10,6,"Images/Sprite.png", temp);
        }
    
        if(_PAR->_LifeOver())
        {
            delete _PAR;
        }
    
        _PAR->_Operate(_RenderTexture);
    
    }
    


  • Oh, oh, Speicherleck.
    Du erzeugst direkt am Anfang des Programmes einen PARTICLE (Solchen Namen sollte man normalerweise nur als Präprozessorkonstante benutzen...) auf dem Heap.
    Dann wird wenn ein Mausbutton gedrückt wird noch einer angefordert ohne den vorigen zu löschen.
    Manuelles Managment ist deshalb blöd. Nutze std::unique_ptr oder - falls du noch kein C++11 Support hast - std::auto_ptr.
    Zumal das hier überflüssig ist und sich mit entsprechenden Settern beheben könnte.



  • OK, aber wenn ich das weg lasse ist _PAR ind void Par() nicht deklariert. Dafür bekomme ich jetzt sicher Prügel, aber kann ich meine Klasse nicht iwi mit NULL aufrufen so das sie Global ist?

    EDIT: Ok, vergessen wir das, wie gesagt, mit Zeiger bin ich noch nicht so im Klaren. Da fehlt mir noch des Verständnis.

    Ich möchte eine kleine Particle Funktion schreiben bei der ich einfach ein Objekt erstelle, dieses lässt zb Funken sprühen, und wenn es fertig ist soll es sich selbst löschen ohne das ich jetzt zusätzliche funktion aufrufe.



  • Ich würde vorschlagen, Du bastelst Dir noch eine ParticleSystem-Klasse. Wenn Du die startest, erzeugt die alle möglichen Partikel. Und die hat dann auch so was wie Update, was die Partikel bewegen lässt. Partikel prüft für jeden Partikel auch, ob er fertig ist. Und wenn er das ist, dann kannst Du ihn von dort aus löschen.

    Das lässt sich z.B. so machen:

    class ParticleSystem
    {
        typedef std::unique_ptr<Particle> ParticlePtr;
        typedef std::vector<ParticlePtr> Particles;
        typedef Particles::iterator ParticleIterator;
    
        Particles particles;
    
    public:
        void Start();
        void Update();
    };
    
    void ParticleSystem::Start()
    {
        // erzeuge Mal 100 Partikel
        for(unsigned int n = 0; n < 100; ++n)
            particles.push_back(new Particle(/* irgendwelche Parameter */)); // weiß gerade nicht, ob unique_ptr-ctor explicit ist
    }
    
    void ParticleSystem::Update()
    {  
        for(ParticleIterator it = particles.begin(); it != particles.end();)
        {
            (*it)->Update(); // (*it)-> verweist auf den Partikel
    
            if((*it)->Finished())
                it = particles.erase(it); // dank unique_ptr wird das automatisch gelöscht
            else
                ++it;
        }
    }
    

    Ungetestet, ist auch nur eine Anregung (und ich bin sicher, da haben ein paar Forenkollegen auch noch einiges dran zu kritisieren ;)). Du kannst auch boost::ptr_vector nehmen, dann hast Du nicht dieses (*it)->

    Vielleicht ist Dir das jetzt auch zu viel, aber die Bestandteile zu lernen würde Dir sicherlich sehr weiterhelfen.



  • Ok dann werde ich mal den ganzen aufbau nochmal überdenken. Danke für die anregung. ABER wäre das erzeugen und löschen von pointer klassen so generel möglich oder ist das voller stuss?



  • Wie, so? Also mit meinem Code wird das Löschen automatisiert, das erzeugt keine Speicherlecks.

    Wenn Du ein Partikel erzeugst, das sich selbst löscht, musst Du jedenfalls ganz schön aufpassen, das kann ich nicht empfehlen. Denn ich schätze Mal, in jedem Frame wird vom Partikel eine Update-Methode oder so aufgerufen? Dann brauchst Du ja sowieso einen Container von Partikeln. Wer auch immer von außen auf das Partikel zugreift, muss das Löschen eben mitkriegen. Und das klappt nicht, wenn sich das Partikel selbst löscht, außer das Löschen wird eben von außen angestoßen und dann nutzt man doch wieder besser Smartpointer...



  • Sicher, dass jedes einzelne Partikel dynamisch angefordert werden soll? Das kann bei vielen kurzlebigen Partikeln zu einem echten Performance-Bottleneck werden.

    Eisflamme, so zu iterieren ist ebenfalls langsam, da vector::erase() alle nachfolgenden Elemente verschiebt. Ich würde eher std::remove_if() verwenden.



  • Ja, das war jetzt nicht groß durchdacht. Man nutzt ja für Partikelsysteme gerne auch Mal eigene Allokatoren oder Pools, das wäre dann wohl besser.

    Auch beim erase hast Du völlig recht.



  • std::remove_if löscht aber die Elemente nicht, sondern schiebt sie nur ans Ende. Um sie wirklich zu löschen wäre ja dann noch immer ein erase notwendig.

    Ist das erase-remove-idiom da wirklich im Vorteil?



  • Ja, weil die Verschiebung der danachfolgenden Elemente der Haupt-Performance-Fresser ist. erase-swap-Idiom (wie auch immer es genau heißt) nutzt eben nur den swap und ein erase mit konstanter Laufzeit.



  • Eisflamme schrieb:

    Man nutzt ja für Partikelsysteme gerne auch Mal eigene Allokatoren oder Pools, das wäre dann wohl besser.

    Man kommt schon mit std::vector<Particle> recht weit. Gerade mit seiner Allokationsstrategie hat man kaum noch Allokationen, nur noch Kopien.

    llllll schrieb:

    Ist das erase-remove-idiom da wirklich im Vorteil?

    Ja, weil das erase() dann einmal am Schluss aufgerufen wird -- die Elemente werden also in linearer Zeit entfernt. Wenn man erase() in jeder Iteration aufruft, hat man quadratische Laufzeit.

    Eisflamme schrieb:

    Ja, weil die Verschiebung der danachfolgenden Elemente der Haupt-Performance-Fresser ist. erase-swap-Idiom (wie auch immer es genau heißt) nutzt eben nur den swap und ein erase mit konstanter Laufzeit.

    Meinst du swap() -and- pop_back() ? Das ist bei Partikelsystemen je nachdem ungünstig, da die Reihenfolge geändert wird. Wenn man keinen Depth-Buffer hat, werden die Partikel also in anderer Reihenfolge gezeichnet, was merkwürdig aussehen kann.



  • Hey, Ich habe mein Problem fürs erste gelöst und bin sehr zufrieden, danke für die tollen Ratschläge.

    Jetzt habe ich noch ne frage, die Sprites sollen sich in die Richtung bewegen in die sie ausgerichtet sind, tun sie aber nicht. Es sieht zwar aus wie eine nette kleine Explosion ^^ aber halt mit verdrehten Bildchen.

    _AllParticle[i]._Position.x += sin(_AllParticle[i]._Sprite.getRotation()) * _AllParticle[i]._Speed;
            _AllParticle[i]._Position.y += cos(_AllParticle[i]._Sprite.getRotation()) * _AllParticle[i]._Speed;
    


  • Bezeichner, die mit Unterstrich und Grossbuchstaben beginnen, sind reserviert. Du darfst diese nicht verwenden!

    Ansonsten, bringst du Grad und Bogenmass durcheinander?



  • Ja ok, ich werde meine Schreibeisse überarbeiten 🙂

    Der Code denn ich gepostet habe ist alles was ich verwende. Keine vorherige berechnung. Rotation ist ein zufallswert zwischen 0 &360.



  • Ja, eben.
    sin und cos brauchen aber Bogenmaß und nicht Gr
    ad.



  • Ok dann schau ich mal. Seit dem ich angefangen habe zu Programmieren fällt mir mein Mathe Defizit erst richtig auf 😕


Anmelden zum Antworten