vector allocation & invalid pointer

0

Przy kilkunastu razowej operacji push_back mój program się wysypuje. Po krótkich oględzinach doszedłem do wniosku ze mam wskaźnik wskazujący na obiekt trzymany w std::vector i gdy kontenerowi zabraknie pamięci i skopiuje wszystkie obiekty do większego obszaru pamięci mój wskaźnik staje się niepoprawny i kończy program. Mam rację? Pierwszy raz się z czymś takim spotykam. Skoro bezpośrednie wskaźniki stają się niepoprawne tak samo jak iteratory, pozostają tylko indeksy co sprawia ze przy wielu realokacjach std::vector staje się dość bezużyteczny/niepraktyczny i lepiej użyć czegoś w stylu std::list gdzie adres pamięci się nie zmienia. Czy wszystko dobrze rozumiem i mam rację?

3

Nie. Vector jest użyteczny ze względu na cache. Lista rozwala go całkowicie. Wiesz vector[idx] to nie jest droga operacja. Sprowadza się do dodania offsetu do adresu bazowego.

Zobacz:

Jest jeszcze deque łącząca zalety vectora i listy. Tzn jest opakowaną listą vectorów.

3

Nawet przy wielu realokacjach std::vector jest wydajniejszy od std::list bo przydziela pamięć dużymi porcjami - zaś przydzielenie pamięci jest wąskim gardłem w takich operacjach.
Owszem można sobie dobrać std::allocator wtedy lista zaczyna dopiero dorównywać wektorowi.
Jak używasz vector to używaj indeksy - nie wskaźniki.

0

To chyba nie jest zbyt powszechna wiedza? Przeglądam często githuba i jeszcze nigdy nie spotkałem się z metodą zwracającą indeks do jakiegoś obiektu. Raczej widywałem wskaźniki do elementów vectora i dziwne ze to wszystko działało, oczywiście jak rozmiar się nie zmienia jest ok ale przecież tego nie można zawsze przewidzieć, a jak jest potrzeba zwiększyć to nie ma jak zrobić update wszystkich wskaźników. Wyjaśni mi ktoś jeszcze różnicę między vector a deque pod względem pamięci? Drugi problem to jeśli mam klase z kontenerem i chcę puścić jakiś jego obiekt na świat zewnętrzy to poza indeksem musiał bym dodać adres kontenera albo zdefiniować sam kontener jako public co nie jest zbyt fajne.(zakładając ze vector będzie rósł a obiekt modyfikowany będzie z zewnątrz na dłużej) Ew. Zamiast vectora używać czegoś w stylu memory pool i wtedy używać wskaźników. Jak to rozgryźć?

0

Możesz użyć ::reserve() wtedy dopóki nie przekroczysz tej pamięci - masz te same adresy.
To że nie znalazłeś - nie oznacza że nie istnieje.

2
Autor napisał(a):

To chyba nie jest zbyt powszechna wiedza?

Jest.

Autor napisał(a):

Przeglądam często githuba i jeszcze nigdy nie spotkałem się z metodą zwracającą indeks do jakiegoś obiektu.

Owszem. Zapytałeś się o poprawność adresu wiec taka odpowiedz otrzymałeś. Nie o praktykę programowania.

Autor napisał(a):

Raczej widywałem wskaźniki do elementów vectora i dziwne ze to wszystko działało, oczywiście jak rozmiar się nie zmienia jest ok ale przecież tego nie można zawsze przewidzieć, a jak jest potrzeba zwiększyć to nie ma jak zrobić update wszystkich wskaźników.

Dlatego jak dodajesz elementy to nie powinieneś zwracać wskaźników do środka buforu vectora. Tzn. taka koncepcja (wskaźnik w środek jakiegoś większego bufora) ma uzasadnienie w niektórych przypadkach jak niskopoziomowe optymalizacje np. dla lepszego wykorzystania cache przez bufory w bibliotece rpc (przykład z fbthrift), ale to inny poziom ;)

Autor napisał(a):

Drugi problem to jeśli mam klase z kontenerem i chcę puścić jakiś jego obiekt na świat zewnętrzy to poza indeksem musiał bym dodać adres kontenera albo zdefiniować sam kontener jako public co nie jest zbyt fajne.

Nie. Jak już to dajesz geter na tej klasie i jak ktoś chce wskaznik do obiektu to piszesz xxx.getObject(idx). Przy czym to samo w sobie nie jest thread safe ;)

Autor napisał(a):

Ew. Zamiast vectora używać czegoś w stylu memory pool i wtedy używać wskaźników. Jak to rozgryźć?

W wektorze możesz trzymać wskaźniki.
Ale nie w tym rzecz. Pytanie brzmi - kto jest właścicielem tego obiektu? Jak zagwarantujesz, że właściciel nie zniszy obiektu jeżeli ktoś inny też go trzyma. Lista też nie rozwiązuje tego problemu. Sposób implementacji zależy od konkretnego przypadku użycia. Przykładowo jeżeli czas życia originalnego kontenera i kogoś kto trzyma uchwyt do obiektu są różne (tzn uzytkownik nie jest zamkniety w jakims lexical scopie z ktorego wynika, że nie przeżyje kontenera) to może trzeba obiekt trzymać jako shared_ptr?

0

Użyj deque zamiast vector. Nie psuje wskaźników na istniejące elementy przy push_back.

1 użytkowników online, w tym zalogowanych: 0, gości: 1