2009-02-24 14 views
12

Posiadam kolekcję polimorficznych obiektów, wszystkie pochodzą z mojej klasy Zwierząt: Kot, Pies i MonkeyFish.Kiedy należy używać wektora obiektów zamiast wektora wskaźników?

Mój zwykły tryb pracy jest do przechowywania tych przedmiotów w wektorze wskaźniki Animal, tak:

std :: vector < Zwierząt *> my_vector;

 
my_vector.push_back(new Animal_Cat()); 
my_vector.push_back(new Animal_Dog()); 
my_vector.push_back(new Animal_MonkeyFish()); 

A życie jest wspaniałe ... czy to prawda?

Niedawno powiedziano mi, że powinienem naprawdę starać się unikać przydzielania pamięci w ten sposób, ponieważ to sprawia, że ​​zarządzanie pamięcią jest uciążliwe. Kiedy muszę zniszczyć my_vector, muszę przerobić wszystkie elementy i usunąć wszystko.

Nie sądzę, że mogę przechowywać wektor referencji (może się mylę), więc wydaje mi się, że przechowywanie wektora obiektów Zwierzęcych jest moją jedyną alternatywą.

Kiedy należy wybrać wektor wskaźników w porównaniu do wektora obiektów? Ogólnie, która metoda jest lepsza? (Chciałbym ograniczyć kopiowanie obiektów w największym możliwym stopniu.)

Odpowiedz

17

Powinieneś używać wektora obiektów, jeśli to możliwe; but in your case it isn't possible.

Pojemniki wskaźników pozwalają uniknąć problemu z krojeniem. Ale musisz wywołać delete na każdym elemencie, tak jak robisz. To denerwujące, ale możliwe. Niestety zdarzają się przypadki (kiedy jest zgłaszany wyjątek), w których nie można mieć pewności, że usuwanie jest poprawnie wywoływane, a skończy się przeciek pamięci.

Głównym rozwiązaniem jest użycie inteligentnego wskaźnika. Pre-C++ 11 jest dostarczany z auto_ptr, but that cannot be used in a standard container. C++ 11 ma std::unique_ptr i std::shared_ptr, które są przeznaczone do użycia w kontenerach (wolę std::unique_ptr, chyba że naprawdę potrzebuję liczenia odwołań). Jeśli nie możesz użyć C++ 11, najlepszym rozwiązaniem jest Boost smart pointers.

+1

The Boost smart pointers wprowadził go do raportu technicznego, więc możesz mieć std :: tr1 :: shared_ptr <>. VC++ 9 w VS 2008 ma. –

+0

dla odniesienia C++ 0x unique_pte, które jest prawie zamiennikiem dla auto_ptr, będzie działało w kontenerach z powodu odniesień rvalue i poruszania semantyką –

8

W takim przypadku przechowywanie wektora Animal nie będzie działać, ponieważ Twoje zwierzęta mają różne rozmiary, a Ty nie będziesz w stanie przechowywać pochodne obiekty w przestrzeniach przeznaczonych do przechowywania klasy bazowej. (Nawet jeśli mają one ten sam rozmiar, nie uzyska się zamierzonego efektu polimorficznego, ponieważ zostaną wykonane metody klasy podstawowej - wirtualność metody nie wchodzi w grę, dopóki nie uzyskasz do niej dostępu za pomocą wskaźnika lub odnośnika.)

Jeśli chcesz uniknąć uciążliwej zarządzania pamięci samemu, można rozważyć przechowywania inteligentnego wskaźnik taki jak shared_ptr (zauważ, że auto_ptr nie działa z kontenerów STL, według Maxa Lybbert), lub jakiś wariant tego. W ten sposób nadal możesz korzystać z klasy polimorficznej, ale to dla ciebie trochę mniej pracy.

Nie ma prawdziwych twardych i szybkich zasad dotyczących używania obiektów i wskaźników, choć warto zauważyć, że w niektórych przypadkach, takich jak twoje, obiekty po prostu nie będą działać dla ciebie. Zwykle używam obiektów, gdy nic nie stoi na przeszkodzie, chociaż musisz pamiętać o kosztownych operacjach kopiowania (choć czasami można je poprawić, przekazując kontenery przez odniesienie).

+0

Huh. Nie wiedział tego. Jak niefortunnie. –

+0

Nigdy nie próbowałem, więc zastanawiam się, dlaczego auto_ptr nie działa z kontenerami STL? –

+0

Ah, tak. Ma sens. –

8

Zamiast używać shared_ptr ze standardowymi kontenerami STL, spójrz na Boost Pointer Container Library. Został zaprojektowany, aby rozwiązać dokładnie ten problem.

1

Jeśli kiedykolwiek usłyszeć argument ale to będzie tak kosztowne, ich struktury skopiować cały czas gdy chcesz używać pełnych obiektów zamiast wskaźników w wektorze, oznacza to 2 główne argumenty są:

  1. Nie musimy się martwić kwestiami dotyczącymi żywotności wskaźników, co oznacza, że ​​nie ma przecieków od , który jest określony (chyba że same struktury mają dane wskaźnika, ale to już inna historia).
  2. Lokalizacja danych sąsiednich struktur w pamięci zwiększy wydajność w typowych scenariuszach użycia, a nie spowolnienie, jak w przypadku pośredniego wskaźnika (względnie).

Dodatkowy koszt kopiowania jest zwykle brany podczas dodawania materiałów do kontenera, a nie podczas korzystania z danych - pomyśl o tym: co robisz najbardziej? dodawać przedmioty lub używać ich?

Jednak przy dodawaniu obiektów polimorficznych wskaźniki są niezbędne, aby uniknąć krojenia.

Powiązane problemy