itereren door een vector met een einde dat kan veranderen

Status
Niet open voor verdere reacties.

Murdocki

Gebruiker
Lid geworden
7 jun 2007
Berichten
449
hallo
ik probeer een vector bij te houden die kan veranderen terwijl er doorheen geitereerd wordt dit doe ik zo:

Code:
void UpdatableEntityData::update()
{
	std::vector< UpdatableEntity* > updatedEntities;

	std::vector< UpdatableEntity* >::iterator pos = updatableEntities.begin(), end = updatableEntities.end();
	while( pos != end )
	{
		if( end != updatableEntities.end() )
		{
			end = updatableEntities.end();
			std::vector< UpdatableEntity* >::iterator tempPos = end - 1, tempBegin = updatableEntities.begin();
			while( (*tempPos) != *(updatedEntities.end() - 1) )
			{
				if( tempPos == tempBegin )
					break;
				else
					tempPos--;
			}
			if( tempPos == tempBegin )
			{
				if( (*tempPos) == *( updatedEntities.end() - 1 ) )
					pos = end;
				else
					pos = tempPos;
			}
			else
				pos = tempPos + 1;
		}
		if( pos == end )
			break;
		else
		{
			updatedEntities.push_back( (*pos) );
			(*pos)->update();
			pos++;
		}
	}
}

echter nu als ik 66 (weet niet of dit precies uitmaakt) entities toe voeg dan krijg ik een error bij pos++. dit is een fatal error. er staat line 163 + 0xf bytes in de laatst aangeroepen code in visual studio debugger. het rare is dat de debugger de waarde van pos(adres) niet weer kan geven en hij zegt dat end naar 0xfeeefeee wijst, terwijl dit helemaal niet het einde is van de vector volgens mij. ziet iemand wat ik fout doe?
ps: het toevoegen en verwijderen lukt gewoon totdat ik een groot aantal ineens toevoeg
 
Ik vind het aparte code. Ik moest er even goed naar kijken voordat ik door had wat er moest gebeuren. (weet het nu nog niet 100% zeker volgens mij :o)

Verder wordt het onderstaande stukje volgens mij nooit uitgevoerd:
Code:
if( end != updatableEntities.end() )
		{
			end = updatableEntities.end(); // end is toch al gelijk aan updatableEntities.end() ? :p
			std::vector< UpdatableEntity* >::iterator tempPos = end - 1, tempBegin = updatableEntities.begin();
			while( (*tempPos) != *(updatedEntities.end() - 1) )
			{
				if( tempPos == tempBegin )
					break;
				else
					tempPos--;
			}
			if( tempPos == tempBegin )
			{
				if( (*tempPos) == *( updatedEntities.end() - 1 ) )
					pos = end;
				else
					pos = tempPos;
			}
			else
				pos = tempPos + 1;
		}

Aangezien deze alleen wordt uitgevoerd wanneer 'end' niet gelijk is aan 'updatableEntities.end()', en dat zal niet gebeuren, aangezien je een paar regels erboven hebt staan 'end = updatableEntities.end()'. 'end' heeft dus de hele tijd dezelfde waarde.

Alleen de onderstaande code wordt dus uitgevoerd:
Code:
	if( pos == end )
			break;
		else
		{
			updatedEntities.push_back( (*pos) );
			(*pos)->update();
			pos++;
		}

Dat eerste if-statement met die break is ook overbodig als ik het goed zie(in deze situatie hoeft er aan geen expliciet statement te worden voldaan). Aangezien je een while-loop hebt met de conditie 'while( pos != end )', en de verhoging van 'pos' helemaal op het einde gebeurt, en daarna wordt de lus dus afgebroken wanneer pos gelijk is aan end.

Verder zou je om van achter naar voren door een vector te gaan ook een reverse_iterator kunnen gebruiken in combinatie met rbegin() en rend(). Daar zijn ze immers voor bedoeld.

Verder heb ik helaas echt geen idee wat je bedoeling precies is. Misschien begrijp ik het beter als je het iets duidelijker uitlegt of als je wat meer code toont.
 
ik heb een engine en een game, de game stopt entities in de engine of verwijdert deze, nou heb ik een probleem als ik een entity verwijder terwijl ik door de vector heen itereer, omdat dan op een gegeven moment de iterator wijst naar een object dat niet meer bestaat.
het idee van de code in de eerste post is als volgt.

while loop door de lijst van entities van begin tot einde.

als het einde is gewijzigd dan moet de positie naar de eerstvolgende entity die nog niet is geupdated geset worden, ook moet het einde van de while loop's check veranderen.

als de positie nu naar het einde wijst dan stoppen.
anders updaten.

mja in theorie zou het moeten werken maar dat doet het niet dus, ik heb het omgebouwd naar de volgende code nu (zou begrijpelijker moeten zijn):

Code:
void UpdatableEntityData::update()
{
	while( entitiesToRemove.size() > 0 )
	{
		removeUpdatableEntity( *entitiesToRemove.begin() );
		entitiesToRemove.erase( entitiesToRemove.begin() );
	}

	std::vector< UpdatableEntity* >::iterator pos = updatableEntities.begin();
	while( pos != updatableEntities.end() )
	{
		if( !isPendingToBeRemoved( (*pos ) ) )
			(*pos)->update();
		pos++;
	}
}
Code:
void UpdatableEntityData::removeUpdatableEntity( UpdatableEntity* entity )
{
	std::vector< UpdatableEntity* >::iterator pos = updatableEntities.begin();

	while( pos != updatableEntities.end() )
	{
		if( (*pos) == entity )
		{
			updatableEntities.erase( pos );
			break;
		}
		pos++;
	}
}
bool UpdatableEntityData::isPendingToBeRemoved( UpdatableEntity* entity )
{
	std::vector< UpdatableEntity* >::iterator pos = entitiesToRemove.begin();
	while( pos != entitiesToRemove.end() )
	{
		if( (*pos) == entity )
			return true;
		pos++;
	}
	return false;
}

het idee hiervan is om eerst alles wat verwijderd moet worden te verwijderen.

dan een loop door alles wat geupdated moet worden.

als het nogsteeds niet verwijderd hoeft te worden (verwijder call komt van een andere thread) dan updaten.

het probleem is nu ... tsja ... hij komt niet altijd naar boven laat me even zoeken waar het precies fout gaat nu

edit:
als ik m'n game nu debug dan krijg ik als output dit: maar geen breakpoints dat ik kan zien waar het fout gaat, ik denk ergens in de game zelf niet in de engine. kan ik dat zien? waar in code deze errors veroorzaakt worden?:

First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xabababab.
First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
First-chance exception at 0x004095c9 in Bomberman.exe: 0xC0000005: Access violation reading location 0x000078da.
A first chance exception of type 'System.AccessViolationException' occurred in Bomberman.exe
First-chance exception at 0x003f4c69 in Bomberman.exe: 0xC000001D: Illegal Instruction.
First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
First-chance exception at 0x52c825ff in Bomberman.exe: 0xC0000005: Access violation reading location 0x52c825ff.
First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
First-chance exception at 0x52c825ff in Bomberman.exe: 0xC0000005: Access violation reading location 0x52c825ff.
First-chance exception at 0x00403afe in Bomberman.exe: 0xC0000005: Access violation reading location 0xfeeefeee.

deze exceptions worden on the run gegenereerd maar worden ook genegeerd door de debugger
 
Laatst bewerkt:
ik heb een engine en een game, de game stopt entities in de engine of verwijdert deze, nou heb ik een probleem als ik een entity verwijder terwijl ik door de vector heen itereer, omdat dan op een gegeven moment de iterator wijst naar een object dat niet meer bestaat.

Ik heb nu niet zo heel veel tijd, maar zou je zo'n entity niet beter op non-actief kunnen zetten zodat je er alsnog door kunt itereren zonder problemen en dan met de update-functie gewoon alles kopiëren wat actief is ?

edit: en trouwens, als je vaak elementen tussenin wilt verwijderen dan kun je volgens mij beter geen vector gebruiken. Daarvoor kun je een geschikter type gebruiken.
 
Laatst bewerkt:
dat actief/non actief heb ik nou ongeveer gerealiseerd dmv die twee vectoren.

wat is dan beter ipv een vector? een linked list ofzo?
 
dat actief/non actief heb ik nou ongeveer gerealiseerd dmv die twee vectoren.

Ik bedoel met actief dat het object gewoon blijft bestaan, alleen dat ie dat gewoon 'uitgeschakeld' is. (hij wordt niet meer naar het scherm getekend en dergelijke)

Dan hoef je er geen rekening mee te houden of de iterator nog geldig is of niet.

wat is dan beter ipv een vector? een linked list ofzo?

Je kunt dan inderdaad het beste een list gebruiken. Deze is geoptimaliseerd voor de handelingen die jij in dit geval wilt uitvoeren.
 
ok even kijken of ik er wel echt een linked list van kan maken. weet je ook hoe ik die accesviolations automatisch een breakpoint kan laten genereren in de debugger van ms vc++?
 
hij gaat nu nogsteeds fout bij pos++, die wijst ineens naar 0xfeeefeee en dit kan de vector's ++ operator niet verwerken. weet iemand wat dat adres voorstelt want het is altijd hetzelfde? anders zal ik even moeten zoeken mja als iemand het al weet ;)
 
ok ik geloof dat ik het gevonden heb, ik dacht met m'n eigenwijze hoofd dat toevoegen vanuit een andere thread wel gewoon kon maar dat kan uiteraard ook niet omdat je dan heel soms toch tegelijk aan hetzelfde adres zit ( dit veroorzaakt de accesviolations ).
0xfeeefeee is een adres waar een iterator heen wijst als hij naar een object wijst wat al gedeleted is DIT IS NIET NULL dus dat kan bij veel tests ook verkeerd gaan maar dit heb ik dus opgelost dmv die isPendingToBeRemoved methode

edit:
dit wil niet zeggen dat het einde veranderen niet kan, zorg er als je het gaat proberen iig voor dat je het binnen dezelfde thread houdt
 
Laatst bewerkt:
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan