• 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()

VPS Starter Arubacloud
0 głosów
345 wizyt
pytanie zadane 10 października 2018 w C i C++ przez żółwibekon Początkujący (300 p.)
zamknięte 15 października 2018 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.
1
komentarz 10 października 2018 przez j23 Mędrzec (194,920 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

+1 głos
odpowiedź 10 października 2018 przez j23 Mędrzec (194,920 p.)
edycja 10 października 2018 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 2018 przez niezalogowany

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 2018 przez żółwibekon Początkujący (300 p.)

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

komentarz 10 października 2018 przez j23 Mędrzec (194,920 p.)
W komentarzu do głównego posta napisałem Ci, co jest powodem błedu.
0 głosów
odpowiedź 11 października 2018 przez mokrowski Mędrzec (155,460 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 2018 przez żółwibekon Początkujący (300 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 2018 przez draghan VIP (106,230 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 2018 przez monika90 Pasjonat (22,940 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 2018 przez draghan VIP (106,230 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 2018 przez żółwibekon Początkujący (300 p.)

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

1
komentarz 14 października 2018 przez monika90 Pasjonat (22,940 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 2018 przez draghan VIP (106,230 p.)
Dzięki bardzo. Fajne źródło. :)

Podobne pytania

0 głosów
2 odpowiedzi 323 wizyt
0 głosów
2 odpowiedzi 423 wizyt
pytanie zadane 6 stycznia 2018 w C i C++ przez Łukasz Michalski Użytkownik (560 p.)
+1 głos
2 odpowiedzi 823 wizyt
pytanie zadane 16 października 2018 w C i C++ przez Drax Użytkownik (630 p.)

92,452 zapytań

141,261 odpowiedzi

319,074 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...