Problem mit List, Iterator und Pointern auf Objekte



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    Wie teste ich mein Programm effektiv auf Memory Leaks ?

    Das Memory Leak ist in der while Schleife. Da braucht man nichts zu suchen!



  • Wie kann ich denn auf die Objekte zugreifen wenn ich die ohne new direkt als ganzes Objekt in der Liste hinterlege ?
    Weil Iterator->Methode() funktioniert irgendwie nicht.



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    funktioniert irgendwie nicht

    ist keine Fehlerbeschreibung



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    while( TimerA >= TimerB) {
    CObjekt *pPointerX = new CObjekt( BspWertA, BspWertB );
    pPointerX->Memberfunktion("BspDateiname.png");
    ObjektListe.push_back(*pPointerX);
    TimerA = 0;
    }

    Was spricht denn gegen:

    while( TimerA >= TimerB) {
       auto object = CObjekt( BspWertA, BspWertB );
       object.Memberfunktion("BspDateiname.png");
       ObjektListe.emplace_back(object);
       TimerA = 0;
    }
    

    Das hat nichts mit Iteratoren zu tun. Iteratoren sind, wie der Name sagt, zum iterieren durch Container und sind irgendwie eine Referenz auf die entsprechende Position im Container, d.h. du kannst über den Iterator auf deine Objekte zugreifen.



  • ...und wenn dein CObjekt Probleme beim Kopieren macht, dann machst du statt deiner std::list<CObject> eben eine std::list<std::unique_ptr<CObject>>. Dann kannst du sowas machen und brauchst kein delete:

    auto pPointerX = std::make_unique<CObjekt>( BspWertA, BspWertB );
    pPointerX->Memberfunktion("BspDateiname.png");
    ObjektListe.push_back(std::move(pPointerX));
    

    (und warum eigentlich std::list statt std::vector - sicher dass du eine Liste brauchst?)



  • @wob
    wenn ich mir die Kopie sparen wollen würde, würde ich wohl sowas machen:

    while( TimerA >= TimerB) {
       ObjektListe.emplace_back(BspWertA, BspWertB );
       ObjektListe.back().Memberfunktion("BspDateiname.png");
       TimerA = 0;
    }
    

    Aber ich glaube, dass, wenn CObjekt nicht Kopierbar ist bzw da Probleme macht, _andi84 noch ganz andere Probleme bekommt.

    Und, weil ich es auch nicht verstehe: Warum list und nicht vector?



  • Ich habe es jetzt hinbekommen:

    So erzeuge ich die Objekte (heißen inzwischen CParticle 😉 ):

                           if (Zeitgeber.GetTimerTicks() >= SpawnTime) {
    
    				SDL_Point StartPos = { 400,300 };
    
    				srand(SDL_GetTicks());
    
    				float fAngle = (float)(rand() % 360);
    
    				SDL_Log("%f", fAngle);
    
    				CParticle* pParticle = new CParticle(StartPos, 0.5, fAngle);
    
    				ParticlesList.push_back(pParticle);
    
    				SpawnTime = Zeitgeber.GetTimerTicks() + 1;
    			}
    

    So werden diese aufgerufen:

                           for (myParticle = ParticlesList.begin(); myParticle != ParticlesList.end(); ++myParticle) {
    				(*myParticle)->Update();
    				(*myParticle)->Render();
    			}
    

    Und so lösche ich diese wieder:

            for (myParticle = ParticlesList.begin(); myParticle != ParticlesList.end();) {
    		delete(*myParticle);
    		myParticle = ParticlesList.erase(myParticle);
    	}
    

    Hoffe es hilft vielleicht irgendwem weiter. Gruß _andi84



  • Warum new und delete? Das ist nicht nötig und sollte vermieden werden.



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    srand(SDL_GetTicks());

    Nein! Einmal!



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

            for (myParticle = ParticlesList.begin(); myParticle != ParticlesList.end(); ++myParticle) {
      		(*myParticle)->Update();
      		(*myParticle)->Render();
      	}
    

    Das kannst du einfacher schreiben:

    for (auto *particle : ParticlesList) {
        particle->Update();
        particle->Render();
    }
    

    ParticlesList hört sich wie eine Klasse an. Ich würde Variablen immer mit Kleinbuchstaben beginnen. Und ist das "List" im Namen notwendig? Schlage Umbenennung in particles vor.



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    float fAngle = (float)(rand() % 360);

    Was tut der Cast hier deiner Meinung nach?



  • @Schlangenmensch

    Ausnahme ausgelöst bei 0x54E7CA8E (SDL2.dll) in SDL2_Klassen_Projekt.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0xDDDDDDDD.

    @manni66

    Habe ich mal geändert.

    @wob

    ParticlesList ist vom Typ std::list<CParticle*>
    myParticle ist vom Typ std::list<CParticle*>::iterator myParticle

    @wob

    Der Cast wandelt hier eine Zahl zwischen 0 und 360 in einen float Wert den ich später in einer
    Funktion benötige.

    MfG _andi84


  • Mod

    Diese ganzen Fragen a la

    Und, weil ich es auch nicht verstehe: Warum list und nicht vector?

    oder

    Was tut der Cast hier deiner Meinung nach?

    wurden dir wahrscheinlich nicht gestellt, weil die Fragenden wirklich eine Erklärung von dir möchten. Denk vielleicht mal darüber nach, was sie wohl eigentlich damit sagen wollten…



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    ParticlesList

    Angenommen du hast als Datenstruktur

    std::listy<CParticle> ParticlesList
    

    dann bekommst du hier:

    CParticle pParticle(StartPos, 0.5, fAngle);
    ParticlesList.push_back(pParticle);
    

    einen Fehler?
    Wenn du das machst darfst du natürlich delete(*myParticle); nicht mehr schreiben. Und (*myParticle)->Update(); wird zu (*myParticle).Update(); und analoge Änderungen.



  • Hier mal die Particle Klasse:

    #ifndef CPARTICLE_HPP
    #define CPARTICLE_HPP
    
    #include "CSDL2_Framework.hpp"
    #include "CSprite.hpp"
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <time.h>
    #include <list>
    
    class CParticle {
    public:
    	CParticle(SDL_Point StartPos, float fSpeed, float fAngle);
    	~CParticle();
    	void Update();
    	void Render();
    	void SetAlive(bool bAlive) { m_bAlive = bAlive; }
    private:
    	CSprite* m_pParticle;
    	bool m_bAlive;
    	float m_fSpeed;
    	std::string m_Dateien[4];
    	Uint32 m_SpawnTime;
    	SDL_Point m_StartPos;
    	float m_fAngle;
    	float m_xPos;
    	float m_yPos;
    };
    
    #endif
    
    // -------------------------------------
    
    #include "CParticle.hpp"
    
    CParticle::CParticle(SDL_Point StartPos, float fSpeed, float fAngle)
    {
    	m_SpawnTime = 0;
    	m_Dateien[0] = "img/p1.png";
    	m_Dateien[1] = "img/p2.png";
    	m_Dateien[2] = "img/p3.png";
    	m_Dateien[3] = "img/p4.png";
    	m_xPos = m_yPos = 0;
    	m_fSpeed = fSpeed;
    	m_pParticle = new CSprite();
    	srand(SDL_GetTicks());
    	Uint32 Zufall = rand() % 4;
    	m_pParticle->Load(m_Dateien[Zufall]);
    	m_StartPos = StartPos;
    	m_pParticle->SetPos(m_StartPos.x, m_StartPos.y);
    	m_xPos = m_StartPos.x;
    	m_yPos = m_StartPos.y;
    	m_pParticle->SetRotation(0);
    	m_pParticle->SetAlpha(255);
    	m_fAngle = fAngle;
    }
    
    CParticle::~CParticle()
    {
    	if (m_pParticle != NULL) {
    		delete m_pParticle;
    		m_pParticle = NULL;
    	}
    }
    
    void CParticle::Update() {
    
    	m_xPos -= cos(m_fAngle * (PI / 180)) * m_fSpeed;
    	m_yPos -= sin(m_fAngle * (PI / 180)) * m_fSpeed;
    
    	m_pParticle->SetPos((int)m_xPos, (int)m_yPos);
    }
    
    void CParticle::Render()
    {
    	m_pParticle->Render();
    }
    
    
    

    Hier die Hauptdatei :

    //#include "vld.h"
    
    #include "CSDL2_Framework.hpp"
    #include "CSpriteSheet.hpp"
    #include "CTimer.hpp"
    #include "CSprite.hpp"
    #include "CText.hpp"
    #include "CParticle.hpp"
    #include <stdlib.h>
    #include <time.h>
    #include <list>
    
    int main(int argc, char *argv[]) {
    
    	srand(SDL_GetTicks());
    
    	std::list<CParticle*> ParticlesList;
    	std::list<CParticle*>::iterator myParticle;
    
    	if (g_pFramework->Init("ttf/opensans.ttf", 32, 800, 600, false)) {
    
    		SDL_Color red = { 255,0,0,255 };
    		SDL_Color black = { 0,0,0,255 };
    
    		CTimer Zeitgeber;
    
    		CSprite Bild;
    		Bild.Load("img/bild.png");
    		Bild.SetPos(g_pFramework->ScreenRect().w / 2 - 50, g_pFramework->ScreenRect().h / 2 - 50);
    		Bild.SetRotation(0);
    		Bild.SetAlpha(255);
    
    		SDL_Point Pos = { 100, 100 };
    
    		CText HalloWelt(Pos, "Hallo SDL2 Welt.", red);
    		HalloWelt.SetAngle(-15);
    
    		CText HalloWelt2(Pos, "Hallo SDL2 Welt.", black);
    		HalloWelt2.SetAngle(0);
    		
    		CSpriteSheet SpriteSheet1;
    
    		SDL_Rect Bildteil;
    		Bildteil.w = 100;
    		Bildteil.h = 100;
    		Bildteil.x = Bildteil.y = 0;
    
    		SpriteSheet1.Load("img/explosion.png", Bildteil, 18, true, 0);
    		SpriteSheet1.SetPos(g_pFramework->ScreenRect().w / 2 - 50, g_pFramework->ScreenRect().h / 2 - 150);
    		SpriteSheet1.SetRotation(0);
    		SpriteSheet1.SetAlpha(255);
    
    		Uint32 SpawnTime = 0;
    
    		// --------------
    
    		bool bRun = true;
    
    
    		Zeitgeber.Start();
    
    		while (bRun) {
    
    			g_pFramework->Clear();
    
    			if (Zeitgeber.GetTimerTicks() >= SpawnTime) {
    
    				SDL_Point StartPos = { 400,300 };
    
    				float fAngle = (float)(rand() % 360);
    
    				SDL_Log("%f", fAngle);
    
    				CParticle* pParticle = new CParticle(StartPos, 0.5, fAngle);
    
    				ParticlesList.push_back(pParticle);
    
    				SpawnTime = Zeitgeber.GetTimerTicks() + 1;
    			}
    
    			for (myParticle = ParticlesList.begin(); myParticle != ParticlesList.end(); ++myParticle) {
    				(*myParticle)->Update();
    				(*myParticle)->Render();
    			}
    
    			Bild.Render();
    
    			HalloWelt.Render();
    			HalloWelt2.Render();
    
    			SpriteSheet1.Update(Zeitgeber.GetTimerTicks());
    			SpriteSheet1.Render();
    
    
    			g_pFramework->Update();
    
    			if (Zeitgeber.GetTimerTicks() >= 10000) {
    				bRun = false;
    			}
    
    		}
    
    		Zeitgeber.Stop();
    
    	}
    
    	for (myParticle = ParticlesList.begin(); myParticle != ParticlesList.end();) {
    		delete(*myParticle);
    		myParticle = ParticlesList.erase(myParticle);
    	}
    
    	g_pFramework->Quit();
    	g_pFramework->Del();
    	
    	return 0;
    }
    

    Hoffe das bringt etwas mehr Einsicht.

    @Schlangenmensch
    Wenn ich das konsequent so mache bekomme ich am Ende eben: Ausnahme ausgelöst bei 0x54E7CA8E (SDL2.dll) in SDL2_Klassen_Projekt.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0xDDDDDDDD.

    So sieht das ganze dann aus... SDL2 Tests.



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    CSprite* m_pParticle;

    Das sieht schon Gefährlich aus. Auch an der Stelle solltest du keinen Pointer verwenden, der mit new initialisiert wird.
    Außerdem möchte ich dir den Link ans Herzen legen: The rule of three/five/zero



  • Genau dasselbe Problem/Vorgehen haben wir gerade ausführlichst in https://www.c-plusplus.net/forum/topic/349894/programm-stürzt-nach-korrekter-ausgabe-ab diskutiert.

    Wenn du ein Objekt kopierst, knallt es.

    Am besten machst du, was @Schlangenmensch gesagt hat.

    Du kannst aber auch mal das CSprite* m_pParticle; durch std::unique_ptr<CSprite> ersetzen und dann statt m_pParticle = new CSprite(); einfach m_pParticle = std::make_unique<CSprite>(); schreiben und ~CParticle komplett löschen. Da, wo es dann wahrscheinlich nicht kompiliert, hast du jetzt ein Problem 🙂

    Und srand soll EINMALIG im Programm aufgerufen werden, also nicht innerhalb von CParticle::CParticle.


  • Mod

    Da wir gar nicht wissen, was ein CSprite ist, würde ich erst einmal davon ausgehen, dass das keine virtuelle Basisklasse ist, bis zum Beweis des Gegenteils. Sprich, dass hier überhaupt keine Indirektion nötig ist.



  • @_andi84 sagte in Problem mit List, Iterator und Pointern auf Objekte:

    Hier die Hauptdatei :

    				float fAngle = (float)(rand() % 360);
    

    Da dieser Fehler noch immer im Programm ist.

    • Es gibt im modernen C++ keinerlei Grund einen C-Cast zu verwenden. Wenn ein Cast notwendig ist, sollte man unbedingt einen C++-Cast nutzen.
    • An dieser Stelle ist kein Cast notwendig.


  • So ich habe hier mal alle Quelldateien in ein ZIP Archiv gepackt. Ist schließlich nur ein Hobbyprojekt und ich will ja noch was lernen. Quelltexte Link


Log in to reply