Czy pod vector'em musi być tablica obiektów a czy może być tablica wskaźników na obiekty.

0

Witam.

Opowiadałem znajomemu trochę o ciekawych rzeczach, które odkryłem gdy w celach edukacyjnych pisałem własną implementację std::vector.
A konkretnie odkryłem wtedy, że nie tak łatwo jest zaimplementować reserve gdy typem przechowywanym są obiekty a nie np inty. Odkryłem wtedy placement new.
No i opowiadam o tym znajomemu, i on mi mówi, że on by to rozwiązał poprzez trzymanie w vectorze tablicy wskaźników na obiekty. Przy czym metoda push tworzyłaby nowy obiekt przez new przekazując oryginalny jako parametr konstruktora. Jestem pewien, że to "wybulwi", że tak się nie da na dłuższą metę, ale nie potrafię od ręki powiedzieć gdzie się pojawi pierwszy problem. Pytanie: gdzie to nie zadziała / w którym miejscu to będzie niezgodne z biblioteką standardową? Dla uproszczenia można przyjąć c++ starszy niż x11 (bez semantyki przenoszenia)

4

vector gwarantuje ciągłość ułożenia elementów, tak jak tablica. Więc pomysł ze wskaźnikami jest niezgodny w samym zamyśle.

Coś takiego jak Ty opisujesz jest zrealizowane przez boost::ptr_vector

1

Wydaje mi się, że dla C++ starszego niż C++11 implementacja std::vector może polegać na tablicy wskaźników na obiekty, bo std::vector::data jest dopiero od C++11 a nic innego nie wymaga tablicy obiektów albo wskaźnika, który by wskazywał na ciągły obszar następujących po sobie elementów. Jednak implementacja iteratora byłaby nieco bardziej skomplikowana.

Przy czym metoda push tworzyłaby nowy obiekt przez new przekazując oryginalny jako parametr konstruktora

Tak samo robi std::vector::push_back, jedynie to nie wywołuje operator new, ale po prostu w placement new jest podawany argument, i obiekt jest kopiowany. Dopiero od C++11 push_back przyjmuje również &&, co pozwala na niekopiowanie obiektu.

Pytanie tylko, po co? Taka implementacja będzie wolniejsza.

0

The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other thanbool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

Pytanie: czy ten wymóg jest uzasadniony? Nie potrzeba tablicy zeby dostac sie do dowolnego ani do dowolnego + 1, wszystko da sie załąwić operatorem [] odpowiednio przeciążonym. Oczywiście wówczas odpada zwracanie wskaźnika na wewnetrzna tablice jako iteraota. (który w zasadzie łamie zasady iteratorów random access, bo nie ma arytmetyki wskaźników wstecz (wsk-n). A iterator tego wymaga.

1

Pytanie: czy ten wymóg jest uzasadniony? Nie potrzeba tablicy zeby dostac sie do dowolnego ani do dowolnego + 1, wszystko da sie załąwić operatorem [] odpowiednio przeciążonym.

Możesz sobie taką klasę napisać, ale std::vector z założenia jest obiektowym opakowaniem tablicy.

Zaletą tego jest, że możesz sobie stworzyć vector i przekazać wskaźnik do funkcji, która operuje na gołej tablicy.

0

Miesiąc po ostatniej wypowiedzi naszła mnie pewna wąptliwość :P

Azarien napisał(a):

... ale std::vector z założenia jest obiektowym opakowaniem tablicy.
Zaletą tego jest, że możesz sobie stworzyć vector i przekazać wskaźnik do funkcji, która operuje na gołej tablicy.

Prosiłbym o jakiś przyklad bo czegoś nie rozumiem. Przekazanie wskaźnika na sam Vector nie zadziała o ile się zgubi info o klsaie vector'a, czyli jeśli funkcja przyjmuje int[] zamiast vector<int>. Natomiast jeśli nie gubimy tego że to vector<int> to przeciążenie operatora zrobi swoje. Co prawda mozna zamiast vectora przekazac v.data() i wtedy to o czym piszesz jak najbardziej ma sens. Tylko że data() weszła do vector'a dopiero w C++11. W związku z tym będę dociekliwy (upierdliwy) i spytam: czy to że z założenia (na poziome imlementacyjnym bo o tym mowa) std::vector jest obiektowym opakowaniem tablicy coś daje w praktyce?

0

Tak, wcześniej robiłeś to za pomocą &vec[0], co, o ile brzydsze, dawało (i gwarantowało) ten sam rezultat.

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