Struct/MAP in struct speichern?

09/10/2013 22:40 Jopsi332#1
Ich versuche momentan in einer Struct den datentyp map zu speichern, aber sobald ich es in der struct in der headerdatei mit reinpacke stirbt das Programm beim start.

sieht ca so aus
Code:
struct EventGift
{
   DWORD dwID;
   int nCount;
   int nPercentage;
};
struct EventMonster
{
   DWORD dwID;
   int nInerval;
   int nPercentage;
   map<DWORD,EventGift> m_aEventGift;
};
class AutoEvent
{
public:
   map<DWORD, EventMonster> m_aEventMonster;
   AutoEvent();
   ~AutoEvent();
   
   void ReadInc();
   void Process();
};
kommentiere ich map<DWORD,EventGIft> m_aEventGift; aus stürzt es nicht mehr ab, nur kann ich so nicht meine werte speichern.
09/10/2013 22:58 Tasiro#2
Das ist nicht der für den Absturz relevante Teil. Mit dem Debugger wirst du den Fehler sicher besser eingrenzen können. Wenn es nicht zu viel ist, kannst du auch den gesamten Quelltext zur Fehlersuche bereitstellen.

Wozu brauchst du eigentlich std::map? Reicht std::vector nicht aus?
09/11/2013 06:28 jacky919#3
Ich weiß nicht, ob das der Fehler ist oder nur beim Einfügen in deinen Beitrag passiert ist, aber in der Klasse AutoEvent wird m_aEventMonster nicht richtig deklariert, also die Typen für das Tenplate sind nicht in den <>-Klammern.
09/11/2013 07:19 Delinquenz#4
Quote:
map<DWORD, EventMonster, m_aEventMonster;
Du hast anscheiennd ein , mit einem > verwechselt.
09/11/2013 21:06 Jopsi332#5
Quote:
Originally Posted by Delinquenz View Post
Du hast anscheiennd ein , mit einem > verwechselt.
ja in der Source ist es richtig, war gerade nur so schnell freihand getippt.


Ich habe map anstatt vector gewählt, da die ID's nicht von 1-10 z.b. gehen, sondern z.b. 22, 105, 160

so kann ich besser auf den einzelnen Datensatz zugreifen.

Quote:
Originally Posted by Tasiro View Post
Das ist nicht der für den Absturz relevante Teil. Mit dem Debugger wirst du den Fehler sicher besser eingrenzen können. Wenn es nicht zu viel ist, kannst du auch den gesamten Quelltext zur Fehlersuche bereitstellen.

Wozu brauchst du eigentlich std::map? Reicht std::vector nicht aus?
Debugger sagt einfach Programm beendet mit Code -5

sobald ich aber diesen teil in der Header auskommentiere läuft alles.

Also MUSS es daran liegen, da ich es in der CPP noch garnicht behandele
09/11/2013 21:20 Schlüsselbein#6
Quote:
Debugger sagt einfach Programm beendet mit Code -5
Dann debugge mal richtig, so mit steppen, breaken, tanzen und so.

Oder zeig mal deinen kompletten Code her.
09/11/2013 21:41 Tasiro#7
Quote:
Originally Posted by Jopsi332 View Post
Ich habe map anstatt vector gewählt, da die ID's nicht von 1-10 z.b. gehen, sondern z.b. 22, 105, 160

so kann ich besser auf den einzelnen Datensatz zugreifen.
Reicht es nicht, über die einzelnen Datensätze auf deren IDs zuzugreifen? Wozu brauchst du eigentlich eine ID?

Quote:
Originally Posted by Jopsi332 View Post
Debugger sagt einfach Programm beendet mit Code -5
F5 drücken ist noch kein Debuggen...

Quote:
Originally Posted by Schlüsselbein View Post
zeig mal deinen kompletten Code her.
09/11/2013 22:37 Jopsi332#8
Quote:
Originally Posted by Tasiro View Post
Reicht es nicht, über die einzelnen Datensätze auf deren IDs zuzugreifen? Wozu brauchst du eigentlich eine ID?

F5 drücken ist noch kein Debuggen...
Ich starte das programm und dann mach ich den reiter debug->attach->und geh auf das programm


Code:
.h
#pragma once
struct EventGift
{
	DWORD	dwID;
	int		nCount;
	int		nPercentage;
};
typedef struct EventMonster
{
	DWORD	dwID;
	int		nInterval;
	int		nPercentage;
	//vector<D3DXVECTOR3> position;
	map<DWORD,EventGift> m_aEventGift;
	CTimer m_Interval;
	EventMonster()
	{
		dwID = 0;
		nInterval = 0;
		nPercentage = 0;
		m_aEventGift.clear();
	}
}m_aEventMonster, *paEventMonster;

class CAutoEvent
{
public:
	map<DWORD,EventMonster> m_aEventMonster;
	CAutoEvent();
	virtual ~CAutoEvent();
	void ReadInc();
	void Process();
};
Code:
.cpp
#include "stdafx.h"
#ifdef __AUTO_EVENT
CAutoEvent::CAutoEvent()
{
	//ZeroMemory(&m_aEventMonster,sizeof(m_aEventMonster));
}
CAutoEvent::~CAutoEvent()
{

}
void CAutoEvent::ReadInc()
{
	CScanner script;
	if( script.Load( "AutoEvent.inc" ) == FALSE )
	{
		Error("Could not load AutoEvent.inc!");
		return ;
	}

	EventMonster pEventMonster;
	ZeroMemory(&pEventMonster, sizeof(pEventMonster));
	script.GetToken();
	while( script.tok != FINISHED )
	{
		if(script.Token == _T("EventMonster"))
		{
			script.GetToken();
			while(script.Token != _T( "}" ))
			{
				pEventMonster.dwID = script.GetNumber();
				script.GetToken();//{
				while(script.Token != _T( "}" ))
				{	
					
					if(script.Token == _T("Intervall"))
					{
						script.GetToken();//=
						pEventMonster.nInterval = script.GetNumber();
					}
					else if(script.Token == _T("percentage"))
					{
						script.GetToken();//=
						pEventMonster.nPercentage = script.GetNumber();
					}
					else if(script.Token == _T("Gift"))
					{
						EventGift pEventGift;
						ZeroMemory(&pEventGift,sizeof(pEventGift));
						script.GetToken();
						while(script.Token != _T("}"))
						{
							if(script.Token == _T("SetGift"))
							{
								BOOL bSkip = FALSE;
								script.GetToken();//(
								pEventGift.dwID = script.GetNumber();
								script.GetToken();//,
								pEventGift.nCount = script.GetNumber();
								script.GetToken();//,
								pEventGift.nPercentage = script.GetNumber();
								script.GetToken();//)
								ItemProp * pItemProp = prj.GetItemProp(pEventGift.dwID);
								
								if(!pItemProp)
								{
									Error("Error AutoEvent ID [Monster %i] Item[%i]",pEventMonster.dwID,pEventGift.dwID);
									bSkip = TRUE;
								}
								map<DWORD,EventGift>::iterator it = pEventMonster.m_aEventGift.find( pEventGift.dwID );
								if( it != pEventMonster.m_aEventGift.end() )
								{}
								else
								{
									Error("Error AutoEvent Duplicatet ItemGift[Monster %i] [ID %i]",pEventMonster.dwID,pEventGift.dwID);
									bSkip = TRUE;
								}
								if(!bSkip)
									pEventMonster.m_aEventGift.insert(make_pair(pEventGift.dwID,pEventGift));
							}
							script.GetToken();
						}
						script.GetToken();
						continue;
						
					}
					else if(script.Token == _T("Positions"))
					{
						script.GetToken();
						while(script.Token!=_T("}"))
						{
							if(script.Token == _T("SetPosition"))
							{
								script.GetToken();//(
								D3DXVECTOR3 vPos;
								vPos.x = script.GetNumber();
								script.GetToken();//,
								vPos.y = script.GetNumber();
								script.GetToken();//,
								vPos.z = script.GetNumber();
								script.GetToken();//)
								//pEventMonster.position.push_back(vPos);
							}
							script.GetToken();
						}
						script.GetToken();
						continue;
					}
					script.GetToken();
				}
				//m_aEventMonster.insert(make_pair(pEventMonster.dwID, pEventMonster));
				pEventMonster.dwID = script.GetNumber(); // ID;
			}
			script.GetToken();
		}
		script.GetToken();
	}
}
void CAutoEvent::Process()
{

}
CAutoEvent g_AutoEvent;
#endif
09/11/2013 23:04 Schlüsselbein#9
Breakpoints sagen dir was?
09/11/2013 23:12 MrSm!th#10
Quote:
ZeroMemory(&pEventMonster, sizeof(pEventMonster));
Da haben wir es doch. Was fällt dir ein, das einfach zu 0en?
std::map hat einen Standardkonstruktur, das Objekt ist nie uninitialisiert - das ist der Vorteil von objektorientierter Programmierung. Du hast doch selbst einen Standardkonstruktor für EventMonster definiert, also wozu diese Zeile?
Durch das 0en des Speichers beschädigst du evtl. den internen Zustand (ich weiß nichts Genaueres über die Implementation von map).

Btw. ist dir bewusst, wofür das Präfix "p" normalerweise verwendet wird? Deine EventMonster Variable ist kein Zeiger, also wozu das p?

Code:
typedef struct EventMonster
{
//...
}m_aEventMonster, *paEventMonster;
Ich bin mir nicht so ganz sicher, ob du weißt, was du da tust.
09/12/2013 07:13 Delinquenz#11
Mal machste ein Struct mit typedef, mal ohne. Du definierst den vermeintlichen Klassenmember (m_aEventMonster) einfach mal global und definierst ihn lokal neu innerhalb der Klasse. Sicher, dass das nicht das Ergebnis von c&p ist?
09/12/2013 16:34 Jopsi332#12
Oh scheiße, das mit typedef und global definiert war nur um was zu testen ._.

Code:
.h
#pragma once
struct EventGift
{
	DWORD	dwID;
	int		nCount;
	int		nPercentage;
};
struct EventMonster
{
	DWORD	dwID;
	int		nInterval;
	int		nPercentage;
	//vector<D3DXVECTOR3> position;
	map<DWORD,EventGift> m_aEventGift;
	CTimer m_Interval;
};

class CAutoEvent
{
public:
	map<DWORD,EventMonster> m_aEventMonster;
	CAutoEvent();
	virtual ~CAutoEvent();
	void ReadInc();
	void Process();
};
das mit dem "p" weiß ich, hab ich gewählt um es besser auseinander zu halten von der KlassenVariable und die die ich in der Funktion nutze.
09/13/2013 02:13 Tasiro#13
Code:
.cpp
#include "stdafx.h"
Du solltest deine Projekteinstellungen ändern. Entweder C/C++ - Vorkompilierte Header - Vorkompilierte Header nicht verwenden oder C/C++ - Erweitert - Erzwungene Includedateien auf stdafx.h setzen.
In der stdafx.h sollten nur Headerdateien inkludiert werden, die sich nicht ändern werden, generell sollte diese Datei möglichst nicht ohne Grund genutzt werden, da durch deren Verwendung die Kompilierzeit unnötig steigen kann: alle Dateien müssen erneut übersetzt werden, wenn du in einer in stdafx.h inkludierten Datei etwas änderst.

Code:
class CAutoEvent
{
public:
	map<DWORD,EventMonster> m_aEventMonster;
	CAutoEvent();
	virtual ~CAutoEvent();
	void ReadInc();
	void Process();
};
Du brauchst virtuelle Destruktoren nur bei virtuellen Methoden (Variablen sollten ein Implementierungsdetail sein). Und wenn der Destruktor als einziges virtuell ist, gibt es keinen Grund, Zeiger oder Referenzen auf CAutoEvents zu erstellen, welche tatsächlich Objekte abgeleiteter Klassen beinhalten. Damit ist ein virtueller Destruktor nicht notwendig.

Code:
CAutoEvent g_AutoEvent;
Du verwendest globale Objekte. Warum?

Code:
#ifdef __AUTO_EVENT
__AUTO_EVENT ist ein für den Compiler reservierter Bezeichner, genau wie jeder andere Bezeichner mit zwei Unterstrichen oder einem führenden Unterstrich und einem darauf folgenden Großbuchstaben, oder einem Bezeichner mit einem führendem Unterstrich im globalen Namensraum. Visual Studio darf dir also deine Festplatte formatieren.
Davon abgesehen verstehe ich nicht, wieso du das brauchst. Wenn ich raten müsste, würde ich auf die stdafx.h tippen...

Code:
	CScanner script;
	if( script.Load( "AutoEvent.inc" ) == FALSE )
CGibt ces cdenn ckeinen cpassenden CKonstruktor cfür CScanner? Und eine Methode wie .good (und möglicherweise noch eine implizite Konvertierung zu bool)?
Mit true, false, TRUE und FALSE sollte nicht verglichen werden. Statt if (b == true) kannst du auch einfach if (b) schreiben, und statt if (b == false) entsprechend if (! b).

Code:
Error("Could not load AutoEvent.inc!");
Ist das... eine globale Funktion? Warum nicht std::cerr oder ein anderes Stream-Objekt?


Code:
void CAutoEvent::ReadInc()
{
	// ein über 100 Zeilen langes Ungetüm
}
Was du in CAutoEvent::ReadInc machen möchtest, nennt sich Syntaxanalyse. Diese wird (normalerweise) von einem Parser durchgeführt, welcher seine Token (normalerweise) von einem Lexer (lexikalischen Scanner) erhält. Ein Parser kann z. B. so aussehen (hier ohne Lexer, mit explizitem Syntaxbaum und mit wenig Templateargumenten - kein node<T>):
09/13/2013 02:56 Master674b#14
Quote:
Code:
throw std::exception ("pure virtual function node::eval called");
Den Hinweis mit pure virtual function call bekommst du ohnehin. Da wird abort aufgerufen, zumindest in der VS implementation. Sehr schönes Beispiel!
09/13/2013 16:42 Tasiro#15
Quote:
Originally Posted by Master674b View Post
Den Hinweis mit pure virtual function call bekommst du ohnehin. Da wird abort aufgerufen, zumindest in der VS implementation.
Und es ist undefiniertes Verhalten. Aber da die Funktion sowieso nie aufgerufen werden sollte und es auch nicht mehr als ein Beispiel ist, und der Aufruf einer rein virtuellen Funktion tatsächlich bestraft werden sollte, ist das in Ordnung. Auch ist mir die Fehlermeldung "pure virtual function call" ein wenig zu... unspezifisch, falls sie mir irgendwann irgendwo als Fehler gemeldet werden sollte.