2009-08-21 17 views
5

Załóżmy, że mam ogólną klasę obiektu i ogólną klasę listy. Chcę zachować listę tych obiektów. Czy powinienem przechowywać je jako List<Object> lub List<Object*>?Przechowywanie listy obiektów

Jeśli używam List<Object> i mam metody takie jak:

if(some_condition) { 
    Object obj; 
    myObjectList.append(obj); 
} 

A moja lista klasa zachowuje tylko odniesienie do obiektu, tak szybko, jak to, że if kończy, obiekt jest niszczony, a obiekt, który wysłałem, staje się nieważny. Tak więc kończę robić coś w stylu:

Object *obj = new Object; 
myObjectList.append(*obj); 

Tak, aby nie został zniszczony. Ale teraz przedmioty są niedorozwinięte, nie? Ponieważ teraz są bezpiecznie przechowywane na liście jako obiekty, a nie na wskaźnikach do obiektów, więc nie mogę wywołać na nich usunięcia ... lub czy zostaną automatycznie zniszczone, gdy zostaną usunięte z listy?

W takim przypadku powinienem prawdopodobnie użyć List<Object*> i usunąć je z listy, gdy skończę, nie?

Tak zagmatwany ... Jestem pewien, że mam gdzieś fundamentalne nieporozumienie.

+0

Problemem jest to, że programujesz jak to jest java ... to nie jest. –

+2

Cóż, nie pochodzę z tła Java ani nic ... Jestem po prostu trochę opóźniony dzisiaj. – mpen

Odpowiedz

6

EDIT: Jak wspomniano w komentarzu boost::ptr_list jest nawet lepiej, ponieważ jest bardziej wydajny i ma ten sam efekt netto jako std::list<boost::shared_ptr<T> >.


EDIT: można wspomnieć, że używasz Qt w swoim komentarzu. Jeśli używasz> = 4,5 można użyć Qt QList i QSharedPointer zajęcia tak:

QList<QSharedPointer<Object> > object_list; 
object_list.push_back(QSharedPointer<Object>(new Object)); 

Polecam użyć std::list<>. Prawdopodobnie chcesz po prostu przechowywać wskaźniki do obiektów, aby nie były kopiowane przez cały czas.

Więc dolnej linii jest:

Powiedzmy, że masz klasę o nazwie Object. Należy to zrobić:

std::list<boost::shared_ptr<Object> > object_list; 
object_list.push_back(new Object); 

dla C++ 11/14, nie ma potrzeby doładowania, po prostu użyć standardowych inteligentnych wskazówek:

std::list<std::shared_ptr<Object>> object_list; 
object_list.push_back(std::make_shared<Object>()); 

za pomocą wspólnych wskaźników, obiekty będą się umyć automatycznie, gdy są usuwane z listy (jeśli nie ma na nie innych obiektów).

Możesz mieć list<Object *>. Ale biorąc pod uwagę twój poziom doświadczenia, uważam, że odniesiony liczony wskaźnik byłby znacznie łatwiejszy w pracy.

W takim przypadku należy prawdopodobnie użyć listy i usunąć je z listy kiedy skończę z nimi, nie?

Tak, to jest realną opcją, ale bardzo polecam inteligentne kursory aby uniknąć „... i usunąć je z listy ...” krok w całości.


UWAGA:

również przykładowy kod dałeś:

Object *obj = new Object; 
myObjectList.append(*obj); 

prawdopodobnie nie jest to, czego chciał, to sprawia, że ​​nowy obiekt na stercie, że kładzie kopię tego na liście. Jeśli po tym nie ma delete obj, to masz wyciek pamięci, ponieważ surowe wskaźniki nie są automatycznie delete d.

+0

Cóż, wolałbym używać QList, ponieważ pracuję z Qt. Ale myślę, że Twoja sugestia nadal działa. – mpen

+0

QList <> będzie działać prawie identycznie jak std :: list <>. Oba są szablonami i oba mogą zawierać wskaźniki/inteligentne wskaźniki. –

+0

QList <> obsługuje również iteratory stylu STL, dzięki czemu są ładne i zgodne z ogólnymi algorytmami C++. –

3

W pierwszym przypadku obiekt jest kopiowany, a tylko oryginał jest niszczony. Inna instancja znajduje się na liście.

W drugiej wersji można użyć narzędzia Lista destruktora, aby usunąć przechowywane obiekty.

+0

Och ... Widzę, co się dzieje. Ponieważ z kodem, nad którym pracuję, mam również inny wskaźnik, który został wstawiony do miksu ... Myślę, że jeden był nieważny, a drugi nie. To wiele wyjaśnia. – mpen

+2

Upewnij się, że masz "głęboki" konstruktor kopii lub możesz uzyskać naprawdę nieoczekiwane wyniki. – DeusAduro

1

Użyj wskaźników, zgodnie z sugestią. Używasz "ogólnych" obiektów, prawdopodobnie klasy bazowej, a lista faktycznie zawiera niektóre pochodne obiekty rzucane do bazy - oznacza to, że musisz przekazać wskaźnik do oryginalnie utworzonego obiektu. W przeciwnym razie usuniesz cały polimorfizm.

To

class Base 
{ 
public: 
    int x; 
    virtual int getData() const { return x; } 
}; 
class Derived : public Base 
{ 
public: 
    int y; 
    virtual int getData() const { return y; } 
}; 

Derived obj1; 
obj1.x = 1; 
obj1.y = 2; 

Base obj2 = obj1; 
cout << obj2.getData(); 

ten wypisze 1, gdyż obj2 jest po prostu kopią części podstawy obj1 i jest naprawdę instancją bazy.

1

Można użyć listy, a następnie, gdy nadszedł czas, aby zwalnianie obiektu na pozycji X, należy użyć coś jak

void erase_object(list* l, int i) { 
    delete (*list)[x] 
    list -> removeObj((*list)[x]); 
} 
2

jak z „wszystkie” rzeczy nie istnieje jedna odpowiedź - diabła w szczegóły tego, co chcesz zrobić lub jakie są twoje ograniczenia.

Jeśli obiekty są lekkie i nie wymagają głębokiego kopiowania, przechowywanie drobiazgów w postaci kopii będzie bardziej efektywne. W przeciwnym razie narzut inteligentnych wskaźników jest więcej niż uzasadniony. Jeśli jesteś polimymorficzny, możesz użyć list szablonów.

Jeśli ważniejsze jest zminimalizowanie kopiowania i wyeliminowanie zbędnego kodu z instancji szablonu, użyj listy inteligentnych wskaźników udostępnionych.

Lub użyj listy nagich wskaźników, użyj nowego/usuń i bądź skrupulatny z posiadaniem wskaźnika.

Każda lista będzie działać jak lista, więc wybór implementacji listy zależy od czynników, które nie są tutaj wymienione.

Powiązane problemy