Kopczak1995 Temat założony przez niniejszego użytkownika |
[C++][STL] Polimorfizm i wskaźniki w kontenerach » 2015-05-01 11:16:59 Witam mam mały problem z biblioteką STL. W projekcie mojej gry zdecydowałem się użyć polimorfizmu dla obiektów wroga i gracza. Wygląda to pi razy oko tak: class Tank;
class Enemy; class Player;
std::list < Tank *> tanks;
Enemy * nowy = new Enemy; tanks.puch_back( nowy );
Player * nowy = new Player; tanks.puch_back( nowy );
Mam jednak problem z dealokacją...
for( auto & tank: tanks ) { if( tank->exist == false ) { delete tank; } } tanks.erase( std::remove( tanks.begin(), tanks.end(), nullptr ), tanks.end() );
Wyszedłem z założenia, że to zwykła lista wskaźników i wywalenie czołgu poprzez delete tank dealokuje co trzeba i pozostanie mi pusty wskaźnik na nullptr ale w rzeczywistości siedzą tam jeszcze jakieś śmieci, co sprawia, że ciężko jest dalej pracować, sypie mi errorami :/ Próbowałem używać destruktorów wirtualnych, czytałem że trzeba je wszędzie umieszczać gdy mamy polimorfizm aby delete mogło "zajarzyć" z którym typem mamy do czynienia, jednak dodanie tego wiele nie pomogło :/ |
|
pekfos |
» 2015-05-01 13:27:13 Wyszedłem z założenia, że to zwykła lista wskaźników i wywalenie czołgu poprzez delete tank dealokuje co trzeba i pozostanie mi pusty wskaźnik na nullptr ale w rzeczywistości siedzą tam jeszcze jakieś śmieci, co sprawia, że ciężko jest dalej pracować, sypie mi errorami :/ |
Więc przypisz nullptr po użyciu delete..? To jakby oczywiste. |
|
Kopczak1995 Temat założony przez niniejszego użytkownika |
» 2015-05-01 13:56:46 Tak w sumie już zrobiłem, tylko nie do końca rozumiem co się stało po dealokacji. Powiedz mi czy dobrze myślę - wskaźnik w kontenerze wciąż wskazuje na tamten adres, lecz po użyciu delete nic tam już nie ma? |
|
kubawal |
» 2015-05-01 14:09:15 Hmmm... dealokuje co trzeba i pozostanie mi pusty wskaźnik na |
Może od razu erase'uj ten element z listy? |
|
Kopczak1995 Temat założony przez niniejszego użytkownika |
» 2015-05-01 15:39:43 Hmmm... Pytanie tylko czy usunie mi to element wraz z tym co zostało zaalokowane? @Edit#include <vector> #include <iostream> using namespace std;
class Pamieciozer { public: vector < long long *> tab; Pamieciozer() { tab.resize( 10000 ); for( auto & x: tab ) { long long * nowy = new long long; x = nowy; } tab.erase( tab.begin(), tab.end() ); } };
int main() { while( true ) { Pamieciozer terefere; } }
A no właśnie nie działa... Taki programik zrobiłem do przetestowania co się z pamięcią robi w menedżerze. Erase nie usunie mi alokacji jaka jest pod adresem wskaźnika. Bez sensu -.- |
|
notabigthreat |
» 2015-05-01 17:02:06 Zamiast wskaźników możesz użyć unique_ptr < Klasa_bazowa > . Zachowuje się on bardzo podobnie do zwykłych wskaźników, tyle że gdy wskaźnik jest usuwany, obiekt jest niszczony. Do składowych dostajesz się normalnie, przy pomocy "strzałki" (" -> "). Potrzebne jest wstawienie linijki: Wskaźników takich nie można kopiować, bo każda kopia pod koniec usunęłaby obiekt i miałoby się kilka delete ów na jeden adres. Jeżeli zachodzi potrzeba, by kilka obiektów współdzieliło między sobą jakiś obiekt przez wskaźniki, alternatywą jest shared_ptr . Wydaje się, że musisz w dodatku zaznaczyć "Have g++ follow the C++11 ISO C++ language standard" w Settings -> Compiler. Dzięki temu rozwiązaniu, nie musisz zawracać sobie głowy usuwaniem tego-a-tamtego wtedy-a-wtedy. Erasowanie od razu wszystko załatwia. Push wygląda jakoś tak (też pi razy oko): tanks.push_back( static_cast < unique_ptr < Tank >>( new Enemy( ) ) );
|
|
pekfos |
» 2015-05-01 17:45:20 Erase nie usunie mi alokacji jaka jest pod adresem wskaźnika. Bez sensu -.- |
To jest bez sensu..? Bez sensu jest większość tego kodu, działanie erase() ma sens, bo jest uniwersalne. Inaczej nie można by działać na wskaźnikach, których nie można zwalniać. Push wygląda jakoś tak (też pi razy oko):
tanks.push_back( static_cast < unique_ptr < Tank >>( new Enemy( ) ) );
|
Słabo to wygląda |
|
Fireho |
» 2015-05-01 19:54:44 - delete usuwa obiekt wskazywany przez wskaźnik, ale zostawia wskaźnik w nienaruszonym staniem(nie ma on wartości nullptr , wciąż pokazuje na to samo miejsce) - erase usuwa sam wskaźnik z listy, ale nie zwalnia samego obiektu pokazywanego przez wskaźnik Podsumowując: jak chcesz usunąć sam obiekt i wywalić wskaźnik na niego z kontenera to musisz dać wtedy delete na wskaźnik(aby usunąć obiekt z pamięci) oraz erase na dany element listy(aby usunąć wskaźnik z listy). Alternatywą jest użycie std::unique_ptr jak wcześniej powiedziano, wtedy będziesz mógł dać samo erase i destruktor zadba o zwalnianie pamięci. No i najlepiej dodawać std::unique_ptr y do listy tak: tanks.emplace_back( new Enemy( ) ); . |
|
« 1 » 2 |