Uzyskiwanie referencji do elementu z std::vector, i niepoprawność tej referencji po zmianie wektora

0

std::vector ma to do siebie, że uzyskiwanie referencji do danego elementu jest niebezpieczne - jeżeli założe, że dany wektor ulegnie zmianie, a ja nadal z tej referencji zamierzam skorzystać.

 std::vector<int> vec;
vec.resize(10, 0);

int& ref = vec.at(2);
vec.remove(vec.begin());

//ref nie wskazuje na ten element na ktory wskazywal

W moim przypadku chciałbym przechować referencje do danych elementów w wektorze, i z nich skorzystać nawet jeżeli wektor ulegnie zmianie. Zanim zacznę zabierać się do "hacków", lub do zmiany rodzaju kontenera - chciałem zapytać, czy jest znane jakieś rozwiązanie na ten problem. Jeżeli jednak rozwiązaniem na to okazało by się - zmiana kontenera na inny, to jakie kontenery nadają się do tego?

1

Jeżeli jednak rozwiązaniem na to okazało by się - zmiana kontenera na inny, to jakie kontenery nadają się do tego?

list

0

Możesz rozważyć użycie inteligentnych wskaźników

0
  1. std::list nie pasuje mi do projektu pod wieloma względami.. Jeden z nich - to że nie ma bezpośredniego dostępu do elementu.

  2. Na jakiej zasadzie? Stworzyć wektor z unique_ptr-ami i je potem alokować dynamicznie? Może jeszcze jakieś pomysły? Z tego co czytałem i czytam, C++11 udostępnie wiele nowych kontenerów. Co prawda u mnie jest trochę inny kłopot z innej beczki - u mnie w kodzie wiele linii kodu zależy od tego jak std::vector jest zbudowany - w wielu miejscach po prostu odnoszę się do elementów za pomocą std::at();. Dopiero gdy się dowiedziałem, że przechowywanie referencji do danego elementu std::vectora jest bezsensowne, bo elementy mogą być realokowane, to wszystko zaczyna się sypać.

1

Działanie vector zakłada że przechowywany wewnątrz element (typ POD lub klasa), powinien posiadać poprawne konstruktory kopiujące i przypisanie. Związane jest to z tym że vector zapewnia zawsze ułożenie elementów w ciągłym obszarze pamięci i w przypadku jego powiększania, następuje ponowna alokacja. Ale o tym pewnie wiesz....
Stąd można zaproponować:

  1. Jak przechowasz w vector wskaźniki do elementów, to kopiowany będzie adres a element docelowy nie będzie kopiowany. Adres się nie zmieni więc czy uzyskasz dostęp do niego poprzez indeks w vector czy będziesz go trzymał w zmiennej, będzie to działało poprawnie. Tylko zadbaj o poprawną destrukcję danych żeby pamięć nie wyciekła.
  2. W C++11 (i nowszych), w vector możesz przechować unique_ptr które posiadają konstruktor przenoszący. Biblioteka standardowa wykrywa teraz czy obiekt posiada taki konstruktor i jeśli jest, jest preferowany zamiast kopiującego. Należy tylko pamiętać że inicjalizacja unique_ptr w vector wymaga (w popularnych przypadkach) wykonania std::move.
  3. W C++11 (i nowszych), w vector możesz przechować shared_ptr które dają się kopiować poprawnie i zliczają referencje. Tu trzeba tylko zadbać aby wykonać poprawne umieszczenie tego inteligentnego wskaźnika w kontenerze. Nie wiem jednak czy potrzebne jest zliczanie referencji i kontrolowana destrukcja.
  4. Nie wiem jakiego typu operacje wykonujesz na danych. Jeśli np. mają one unikalne wartości to kontener set będzie ok, jak szukanie ma być szybkie to map lub unordered_map dla kontenera nieposortowanego. O list już pisał kolega... Nie sądzę żeby multimap był Ci potrzebny ale precyzyjnie to nie wiem :-)
0

Wykorzystam std::vector<std::unique_ptr<.....>>, ewentualnie potem jeszcze pokombinuje... Co prawda będzie mnie to kosztować dereferencje wykorzystując mechanizmy unique_ptr-a za każdym razem gdy będę się odnosił do elementu .at(i)... ale na razie się o to nie martwie, bo tych elementów nie ma aż tak dużo.

1

Jeśli masz dostęp do Boosta to możesz użyć stable_vector, który wydaje się właśnie tym, czego szukasz.

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