Problem mit List, Iterator und Pointern auf Objekte



  • @_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



  • Wenn ich schnell richtig geguckt habe, verletzen all deine Klassen, also insbesondere auch CSprite und CText, die Dreierregel.

    Es gab gerade in https://www.c-plusplus.net/forum/topic/349894/programm-stürzt-nach-korrekter-ausgabe-ab/ eine ausführliche Diskussion über das Problem. Bitte lies das und versuche zu verstehen, was bei dir warum problematisch ist und wie es besser geht.



  • /*
    die Aufgabe lautete wie folgt: "Implementieren Sie eine Klasse Student, die einen Namen, Vornamen (beides als char*), eine Matrikelnummer und das Fachsemester (beides unsigned int) enthält. 
    Implementieren Sie eine weitere Klasse Verwaltung, die ein Array von Studenten enthält. Diese Klasse soll neue Studenten anlegen..."
    */
    
    #include <iostream>
    #include <list>
    
    class Student {
    public:
    	Student(const char ChVorname[], const char ChName[], unsigned int nMartikelnummer, unsigned int nFachsemester);
    	~Student();
    	void Ausgabe() {
    		std::cout << pVorname << " " << pName << std::endl;
    	}
    private:
    	const char* pVorname;
    	const char* pName;
    	unsigned int m_nMartikelnummer;
    	unsigned int m_nFachsemester;
    };
    
    Student::Student(const char ChVorname[], const char ChName[], unsigned int nMartikelnummer, unsigned int nFachsemester){
    	pVorname = ChVorname;
    	pName = ChName;
    	m_nMartikelnummer = nMartikelnummer;
    	m_nFachsemester = nFachsemester;
    
    }
    
    Student::~Student() {
    
    }
    
    class Verwaltung {
    public:
    	Verwaltung(unsigned int nAnzahlStudenten);
    	~Verwaltung();
    	void Ausgabe();
    private:
    	unsigned int m_nAnzahlStudenten;
    	std::list<Student> m_StudentenListe;
    	std::list<Student>::iterator m_Student;
    };
    
    Verwaltung::Verwaltung(unsigned int nAnzahlStudenten) {
    
    	m_nAnzahlStudenten = nAnzahlStudenten;
    
    	char chVorname[100];
    	char chName[100];
    	int nMartikelnummer = 0;
    	int nFachsemester = 0;	
    
    	for (unsigned int i = 0; i < m_nAnzahlStudenten; i++) {
    		std::cout << std::endl << "Vorname:";
    		std::cin >> chVorname;
    		std::cout << std::endl << "Name:";
    		std::cin >> chName;
    		std::cout << std::endl << "Martikelnummer:";
    		std::cin >> nMartikelnummer;
    		std::cout << std::endl << "Fachsemester:";
    		std::cin >> nFachsemester;
    
    		Student StudentX(chVorname, chName, nMartikelnummer, nFachsemester);
    		StudentX.Ausgabe();
    		m_StudentenListe.push_back(StudentX);
    	}
    	
    }
    
    Verwaltung::~Verwaltung() {
    	for (m_Student = m_StudentenListe.begin(); m_Student != m_StudentenListe.end(); ++m_Student) {
    		m_Student = m_StudentenListe.erase(m_Student);
    	}
    }
    
    void Verwaltung::Ausgabe() {
    	for (m_Student = m_StudentenListe.begin(); m_Student != m_StudentenListe.end(); ++m_Student) {
    		m_Student->Ausgabe();
    	}
    }
    
    int main()
    {
    	Verwaltung Univerwaltung(2);
    	Univerwaltung.Ausgabe();
    }
    
    

    Ich habe mir das mal durchgelesen und versucht eine Lösung zu finden. Dies ist mein Lösungsansatz für das Problem aus dem anderen Beitrag. Und hier verstehe ich nun nicht warum es keine Ausgabe gibt.



  • @_andi84

    keine Ausgabe

    Keine? Glaub ich nicht.



  • @_andi84 Stand in dem anderen Beitrag nicht auch irgendwo, dass die Aufgabe sch**** ist?

    Schmeiß erstmal alles char* und char[] weg und ersetze sie durch std::string. Dann ersetz std::list durch std::vector.
    Außerdem schmeißt du noch deine Custom Destruktoren weg.

    Dann guckst du dir mal Range based loops an.



  • Ich wollte insbesondere auf die Dinge hinaus, die @SeppJ dort geschrieben hatte. Also zur Resourcenverwaltung.

    Bei dir konkret ist das Problem gewesen, dass du im Konstruktor das SDL-Objekt erzeugst mit irgend so einer SDL-Funktion (das entspricht einem "new") und dann im Destructor das SDL-Destroy (also praktisch ein delete) aufrufst. Wenn du dann dein CSprite kopierst, zerstörst du dasselbe Objekt 2x. Daher unbedingt mal die Dreierregel anschauen. Am besten ist es, wenn du die "Rule of Zero" befolgen kannst (https://en.cppreference.com/w/cpp/language/rule_of_three). Das bedeutet, dass du das SDL-Objekt irgendwie wrappen müsstest. Oder entfernst schnell den Copy-Constructor.

    Ich kenne mich mit SDL allerdings nicht aus - weiß nicht so recht, wie da die normalen Muster aussehen.

    PS: möchte @Schlangenmensch noch unterstützen: warum zur Hölle wollen so viele Neulinge hier std::string nicht nutzen und lieber selbst mit char* herumfrickeln?!


Anmelden zum Antworten