Usuwanie z wektora w zagnieżdżonej pętli

0

Witam mam problem z usuwaniem elementu w wektorze. Sprawa wygląda tak, że mam wektor wskaźników na klasę Bullet i wektor wskaźników na klasę Unit moja pierwsza pętla iteruje po wektorze Bullets i zaczyna się w środku iterowanie po wszystkich przeciwnikach. Chciałbym, żeby to działało tak, że jak któraś z kul trafi w któregoś z przeciwników to jest ona usuwana, ale jak robię to za pomocą erase to dostaję błąd i wydaje mi się, że nie powinienem usuwać nic z wektora bullet do momentu przejścia przez cały wektor. Dlatego staram się zapisywać, które elementy chcę usunąć i po wykonaniu obu pętli to zrobić. Próbowałem czegoś takiego:

void Game::dynamicAcctions(std::vector<Unit*> &enemyUnits, std::vector<Bullet*> &bullets)
{
       std::vector<Bullet*>::iterator remove = deleteBullets(enemyUnits,bullets);
       bullets.erase(remove, bullets.end());
}



std::vector<Bullet*>::iterator Game::deleteBullets(std::vector<Unit*> enemyUnits, std::vector<Bullet*> bullets)
{
       std::vector<Bullet*>::iterator remove = std::remove_if(bullets.begin(), bullets.end(),
               [&](Bullet* x)
               {
               for (std::vector<Unit*>::iterator it = enemyUnits.begin(); it != enemyUnits.end(); ++it)
               {
                       if (x->collision->checkCollision((*it)->collision))
                       {
                               return true;
                       }
                       else
                       {
                               return false;
                       }
               }
               });
       return remove;
}
Ale nie działa, dostaję Expression: vector erase iterator outside range.
2

Przy usuwaniu elementów z vectora warto pamiętać, że już po pierwszym usunięciu iterator się deaktualizuje.
Po drugie: mówiłeś o dwóch pętlach:

moja pierwsza pętla iteruje po wektorze Bullets i zaczyna się w środku iterowanie po wszystkich przeciwnikach.

podczas gdy ja tu widzę tylko jedną, albo czegoś nie rozumiem, albo nie pokazałeś reszty tego fragmentu.
Nie podajesz też w której linijce leci Ci ten wyjątek.

Poza tym, posługujesz się surowymi wskaźnikami - wątpię by tutaj miało to znaczenie, ale na takie coś lepiej uważać, bo gdzieś indziej to, na co wskazują może żyć swoim życiem.


Jakiś czas temu napisałem prostą bibliotekę ułatwiającą pewne operacje na std::vector.
Sprawdź: ExtendedVector

2

Jak nie masz nowego kompilatora, użyj idiomu remove-erase, w przeciwnym wypadku std::erase_if

3

błąd się kryje tu:

std::vector<Bullet*>::iterator Game::deleteBullets(std::vector<Unit*> enemyUnits, std::vector<Bullet*> bullets)

Operujesz na kopiach wektora, a na koniec zwracasz iterator do wektora, którego czas życia właśnie się koczy (bo to kopia).

Na dodatek ta pętla, która wykonuje zawsze jedną iterację (nie taki był plan).
Ta lambda jest za długa, lepiej zdefiniować osobna funkcję.

0

Jak już @MarekR22 napisał, ta lambda sprowadza Ci się do tego:
[to jest kod błędny]

            [&](Bullet* x) {
                for (std::vector<Unit*>::iterator it = enemyUnits.begin(); it != enemyUnits.end(); ++it) {
                        return (x->collision->checkCollision((*it)->collision));
                } 
            }

A miało chyba być coś +- takiego (piszę na oko także nie bijcie jak się nie skompiluje):

    [&](auto x) {
                std::find_if(enemyUnits.begin(), enemyUnits.end(); [x](auto y) {
                        return (x->collision->checkCollision((y)->collision));
		}) != enemyUnits.end();
     }

Ew. możesz zobaczyć filter_iterator z boosta, ale to raczej moja luźna myśl na gorąco i się do niej nie przywiązuj zanadto ;)
Druga rzecz: weź wektor przez referencję albo po STLowemu przekaż iteratory przez wartość

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.