• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Usuwanie elementu tablicy po spełnieniu warunku za pomocą funkcji erase()

0 głosów
184 wizyt
pytanie zadane 10 października w C i C++ przez żółwibekon Początkujący (280 p.)
zamknięte 15 października przez żółwibekon

Cześć, tak jak w tytule mam problem z użyciem metody erase() na mojej tablicy. Chodzi o to aby po spełnieniu warunku, w tym wypadku wyjściu pocisku poza teksturę mapy, usuwało z kontenera owy pocisk, ale za nic na świecie program nie chce się skompilować, a mógłbym przysiąc, że z rok temu jeszcze to działało. Więcej kodu niż ten wycinek nie potrzeba, ponieważ problem leży tylko i wyłącznie tutaj..

 

std::vector<Bullet> bullets;

Tutaj dodaję do tablicy nowe obiekty:

Bullet bullet(400);
if (player->isAttacking()) {
		bullet.setPosition(playerCenter);
		bullet.setVelocity(aimDirectionNormalize);
		bullets.push_back(bullet);
	}

A tutaj w warunku występuje błąd:

for (int i = 0; i < bullets.size(); i++)
	{
		sf::Vector2u gametextureSize = gameTexture->getSize();
		sf::Vector2f bulletPosition = bullets[i].getPosition();

		if (bulletPosition.x < 0 || bulletPosition.x > gametextureSize.x ||
			bulletPosition.y < 0 || bulletPosition.y > gametextureSize.y)
			bullets.erase(bullets.begin() + i);
	}

Już z dwie godziny spędziłem na zagranicznych forach żeby znaleźć rozwiązanie, ale nie za bardzo rozumiem. Bo z tego co się dowiedziałem to muszę posłużyć się iteratorem. No ok, tylko że jak potem mam się za jego pomocą odwołać do metod moich obiektów klasy Bullet? Oczywiście jeśli dobrze rozumuję, ale chciałbym aby mi to ktoś lepiej objaśnił.

A i zapomniałbym. Oto błąd: 


Błąd    C2280    „Bullet &Bullet::operator =(const Bullet &)”: próba odwania do usuniętej funkcji.


Pozdrawiam

żółwibekon

komentarz zamknięcia: Problem rozwiązany.
2
komentarz 10 października przez j23 Maniak (74,360 p.)

Oto błąd: [...]

Wygląda na to, że klasa Bullet (lub któreś z jej pól) ma usunięty lub niezaimplementowany operator przypisania. vector wymaga obecności tego operatora i ctora kopiującego.

3 odpowiedzi

+2 głosów
odpowiedź 10 października przez j23 Maniak (74,360 p.)
edycja 10 października przez j23

Coś w ten deseń:

auto gametextureSize = gameTexture->getSize();

auto it = std::remove_if(bullets.begin(), bullets.end(), [&gametextureSize](Bullet &bullet) {
	
	auto bulletPosition = bullet.getPosition();

	return (bulletPosition.x < 0 || 
		bulletPosition.x > gametextureSize.x || 
		bulletPosition.y < 0 || 
		bulletPosition.y > gametextureSize.y);
});


bullets.erase(it, bullets.end());

 

komentarz 10 października przez Hipcio Maniak (74,620 p.)

Gdyby gameTexture był typu sf::Sprite* to całość można by skrócić:

auto it = std::remove_if(bullets.begin(), bullets.end(), [&gameMap](Bullet &bullet) {
     return !gameMap->getGlobalBounds().contains(bullet.getPosition());
});
bullets.erase(it, bullets.end());
komentarz 10 października przez żółwibekon Początkujący (280 p.)

@j23, Nadal ten sam błąd przy kompilacji

komentarz 10 października przez j23 Maniak (74,360 p.)
W komentarzu do głównego posta napisałem Ci, co jest powodem błedu.
0 głosów
odpowiedź 11 października przez mokrowski Szeryf (88,240 p.)

Jeśli wykonujesz erase(..) kontenerze std::vector, następuje unieważnienie wszystkich iteratorów (a więc i wielkości) kontenera. Stąd masz ten błąd.

To warto zapamiętać. W takich przypadkach stosuje się idiom językowy erase-remove. Tu o nim przeczytasz: https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

O ile @j23 miał częściowo rację co do swojej propozycji (a zakładam że miał), to będzie to wyglądało jakoś tak:

auto gametextureSize = gameTexture->getSize();

bullets.erase(std::remove_if(bullets.begin(), bullets.end(), [&gametextureSize](Bullet &bullet) {
    auto bulletPosition = bullet.getPosition();
    return (bulletPosition.x < 0 || 
        bulletPosition.x > gametextureSize.x || 
        bulletPosition.y < 0 || 
        bulletPosition.y > gametextureSize.y);
}), bullets.end());
0 głosów
odpowiedź 12 października przez żółwibekon Początkujący (280 p.)

Cześć, po paru dniach męczarni znalazłem w końcu sposób na rozwiązanie mojego problemu. Rozwiązania kolegów niżej są bardzo fajne i na pewno skorzystam z funkcji lambda, jednak zdecydowałem się mimo wszystko napisać rozwiązanie w razie gdyby ktoś również w przyszłości miał ten sam problem.

Otóż kompilacja nie dochodziła do skutku, dlatego że w klasie Bullet miałem zadeklarowaną zmienną "speed" typu const float, a za pomocą mojego (jedynego) konstruktora przypisywałem jej wartość podaną w argumencie przy każdym utworzeniu nowego obiektu tejże klasy. Oczywiście po usunięciu słowa kluczowego const wszystko zaczęło działać bez problemu. Do końca nie rozumiem dlaczego, przecież nie była to zmienna statyczna, a wartość zmiennej przypisywałem od razu po utworzeniu obiektu. Może ktoś miły wytłumaczy to bardziej w odpowiedzi na ten post.

Postanowiłem, że ten post będzie rozwiązaniem mojego problemu. Nie wiem czy nie naruszę w ten sposób regulaminu, ale w gdybym jednak to zrobił to z góry przepraszam.

Dziękuje wszystkim za pomoc.

Pozdrawiam

żółwibekon

komentarz 13 października przez draghan VIP (102,260 p.)

a za pomocą mojego (jedynego) konstruktora przypisywałem jej wartość podaną w argumencie przy każdym utworzeniu nowego obiektu tejże klasy. Oczywiście po usunięciu słowa kluczowego const wszystko zaczęło działać bez problemu.

A nie usunąłeś też przypadkiem tego konstruktora? :)

1
komentarz 13 października przez monika90 Pasjonat (17,760 p.)
Operacja erase wymaga od typu elementów by były MoveAssignable, co w uproszczeniu oznacza że muszą mieć operator przypisania. Normalnie kompilator by sam utworzył ten operator, ale nie może tego zrobić gdy klasa ma niestatyczną składową stałą.
komentarz 13 października przez draghan VIP (102,260 p.)

nie może tego zrobić gdy klasa ma niestatyczną składową stałą

Moniko, widzisz gdzieś tutaj potwierdzenie tego? Albo w jakimś innym źródle? Nie mogę znaleźć, a nie mam wykupionej licencji ISO żeby zajrzeć do standardu. :|

komentarz 14 października przez żółwibekon Początkujący (280 p.)

Nie, nie usunąłem konstruktora, a jedynie znacznik const z argumentów konstruktora i w klasie.

1
komentarz 14 października przez monika90 Pasjonat (17,760 p.)

@draghan,

Tu masz listę sytuacji które uniemożliwiają kompilatorowi zdefiniowanie operatora przypisania: http://eel.is/c++draft/class.copy.assign#7

 

komentarz 16 października przez draghan VIP (102,260 p.)
Dzięki bardzo. Fajne źródło. :)

Podobne pytania

0 głosów
2 odpowiedzi 115 wizyt
0 głosów
2 odpowiedzi 100 wizyt
pytanie zadane 6 stycznia w C i C++ przez Łukasz Michalski Początkujący (410 p.)
+1 głos
2 odpowiedzi 140 wizyt
pytanie zadane 16 października w C i C++ przez Drax Początkujący (380 p.)
Porady nie od parady
Zadając pytanie postaraj się o poprawną pisownię i czytelne formatowanie tekstu.Kompozycja

56,370 zapytań

101,067 odpowiedzi

208,200 komentarzy

28,041 pasjonatów

Przeglądających: 333
Pasjonatów: 11 Gości: 322

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...