Tablice a wektory: wstępne podobieństwa i różnice [zamknięte]

111

Jakie są różnice między tablicą a wektorem w C ++? Przykładem różnic mogą być biblioteki, symbolika, umiejętności itp.

Szyk

Tablice zawierają określoną liczbę elementów określonego typu. Aby kompilator mógł zarezerwować wymaganą ilość miejsca podczas kompilacji programu, należy określić typ i liczbę elementów, które będzie zawierać tablica, gdy zostanie zdefiniowana. Kompilator musi być w stanie określić tę wartość podczas kompilacji programu. Po zdefiniowaniu tablicy należy użyć identyfikatora tablicy wraz z indeksem, aby uzyskać dostęp do określonych elementów tablicy. [...] tablice są indeksowane przez zero; to znaczy, pierwszy element ma indeks 0. Ten schemat indeksowania wskazuje na ścisły związek w C ++ między wskaźnikami i tablicami oraz reguły, które język definiuje dla arytmetyki wskaźników.

- Dokumentacja kieszonkowa C ++

Wektor

Wektor to sekwencja obiektów o dynamicznej wielkości, która zapewnia operator[]losowy dostęp w stylu tablicy . Funkcja członkowska push_backkopiuje swoje argumenty za pomocą konstruktora kopiującego, dodaje tę kopię jako ostatni element w wektorze i zwiększa jej rozmiar o jeden.pop_backrobi dokładnie odwrotnie, usuwając ostatni element. Wstawianie lub usuwanie elementów z końca wektora zajmuje zamortyzowany stały czas, a wstawianie lub usuwanie z dowolnego innego miejsca zajmuje czas liniowy. To są podstawy wektorów. Jest ich o wiele więcej. W większości przypadków wektor powinien być pierwszym wyborem zamiast tablicy w stylu C. Przede wszystkim mają dynamiczne rozmiary, co oznacza, że ​​mogą rosnąć w razie potrzeby. Nie musisz przeprowadzać wszelkiego rodzaju badań, aby znaleźć optymalny rozmiar statyczny, jak w przypadku tablic C; wektor rośnie w razie potrzeby i można go ręcznie zmienić na większy lub mniejszy, jeśli zajdzie taka potrzeba. Po drugie, wektory oferują sprawdzanie granic za pomocą atfunkcji składowej (ale nie za pomocąoperator[]), dzięki czemu możesz coś zrobić, jeśli odwołasz się do nieistniejącego indeksu, zamiast po prostu obserwować awarię programu lub gorzej, kontynuując wykonywanie z uszkodzonymi danymi.

- Książka kucharska C ++

Trancot
źródło
Najbardziej podstawowa różnica: są cele, dla których wektor jest dobrym wyborem.
Jerry Coffin
1
„wyczerpujący” i „konsensus” są ortogonalne. Oznacza to, że nie tylko jedno nie implikuje drugiego, ale nie są one nawet w tej samej skali.
Wyścigi lekkości na orbicie
2
Jestem naprawdę zdenerwowany, gdy ludzie, którzy zamykają pytania, są dokładnie tymi informacjami, których szukam. Zdarza się to zbyt często.
Robert Tamlyn

Odpowiedzi:

142

tablice:

  • są konstrukcją języka wbudowanego;
  • pochodzą prawie niezmodyfikowane z C89;
  • dostarczają tylko ciągłą, indeksowalną sekwencję elementów ; żadnych dzwonków i gwizdków;
  • mają stały rozmiar; nie możesz zmienić rozmiaru tablicy w C ++ (chyba że jest to tablica POD i jest zaalokowana malloc);
  • ich rozmiar musi być stałą czasu kompilacji, chyba że są przydzielane dynamicznie;
  • zajmują przestrzeń dyskową w zależności od zakresu, w którym je zadeklarujesz;
  • jeśli są przydzielane dynamicznie, należy je jawnie cofnąć;
  • jeśli są przydzielane dynamicznie, po prostu otrzymujesz wskaźnik i nie możesz określić ich rozmiaru; w przeciwnym razie możesz użyć sizeof(stąd powszechny idiom sizeof(arr)/sizeof(*arr), który jednak zawiedzie po cichu, gdy zostanie użyty nieumyślnie na wskaźniku);
  • w większości sytuacji automatycznie rozpadają się na wskaźniki; w szczególności dzieje się tak przy przekazywaniu ich do funkcji, która zwykle wymaga przekazania osobnego parametru określającego ich rozmiar;
  • nie można zwrócić z funkcji;
  • nie mogą być kopiowane / przypisywane bezpośrednio;
  • dynamiczne tablice obiektów wymagają domyślnego konstruktora, ponieważ wszystkie ich elementy muszą być najpierw skonstruowane;

std::vector:

  • jest klasą szablonu;
  • jest konstrukcją tylko w C ++;
  • jest implementowana jako tablica dynamiczna ;
  • dynamicznie rośnie i kurczy się;
  • automatycznie zarządzają swoją pamięcią, która zostaje uwolniona po zniszczeniu;
  • mogą być przekazywane / zwracane z funkcji (przez wartość);
  • można skopiować / przypisać (wykonuje to głęboką kopię wszystkich przechowywanych elementów);
  • nie rozpadają się wskaźnikami, ale może wyraźnie uzyskać wskaźnik do swoich danych ( &vec[0]jest gwarantowana do pracy zgodnie z oczekiwaniami);
  • zawsze przenosi wraz z wewnętrzną tablicą dynamiczną jej rozmiar (ile elementów jest aktualnie przechowywanych) i pojemność (ile elementów można przechowywać w aktualnie przydzielonym bloku);
  • wewnętrzna tablica dynamiczna nie jest alokowana wewnątrz samego obiektu (który zawiera tylko kilka pól „księgowych”), ale jest alokowana dynamicznie przez alokator określony w odpowiednim parametrze szablonu; domyślny pobiera pamięć z freestore (tzw. sterty), niezależnie od tego, gdzie jest przydzielony rzeczywisty obiekt;
  • z tego powodu mogą być mniej wydajne niż „zwykłe” tablice dla małych, krótkotrwałych tablic lokalnych;
  • podczas realokacji obiekty są kopiowane (przenoszone, w C ++ 11);
  • nie wymaga domyślnego konstruktora dla przechowywanych obiektów;
  • jest lepiej zintegrowany z resztą tak zwanego STL (dostarcza begin()/ end()Methods, zwykłe STL typedef, ...)

Weź również pod uwagę „nowoczesną alternatywę” dla tablic - std::array; W innej odpowiedzi opisałem już różnicę między std::vectora std::array, warto się temu przyjrzeć.

Matteo Italia
źródło
1
Dziękuję @MatteoItalia. Przydałaby się jedna lub dwie referencje.
Trancot
1
@Trancot: każda dobra książka C ++ będzie odpowiednia.
Matteo Italia
6
@Trancot: Naprawdę nie mogę dać ci dużo lepszych referencji - różnice, które zostały podkreślone w tym poście, pochodzą z wielu różnych części Standardu i są lepiej zrozumiałe przy pomocy dobrego podręcznika C ++.
Matteo Italia
Przykład tak obszernego opisu byłby świetny!
carloswm85
26

Dodam, że tablice są konstrukcjami bardzo niskiego poziomu w C ++ i podczas „uczenia się lin” powinieneś starać się trzymać od nich jak najdalej - nawet Bjarne Stroustrup to zaleca (jest projektantem C ++).

Wektory są bardzo zbliżone do tej samej wydajności co tablice, ale z wieloma udogodnieniami i funkcjami bezpieczeństwa. Prawdopodobnie zaczniesz używać tablic podczas łączenia się z interfejsami API, które zajmują się surowymi tablicami lub podczas budowania własnych kolekcji.

John Källén
źródło
1
Interfejs programu aplikacji: ( en.wikipedia.org/wiki/API ). Jest to zbiór punktów wejścia do jednostki oprogramowania (pakietu, biblioteki, systemu operacyjnego). Niektóre interfejsy API będą miały punkty wejścia, takie jak strcat (char * dst, char * src), gdzie dst i src są traktowane jako tablice znaków (nawet jeśli sygnatura funkcji implikuje wskaźniki do znaków).
John Källén,
11

Te odniesienia w dużej mierze odpowiedziały na twoje pytanie. Mówiąc najprościej, długości wektorów są dynamiczne, a tablice mają stały rozmiar. używając tablicy, określasz jej rozmiar w deklaracji:

int myArray[100];
myArray[0]=1;
myArray[1]=2;
myArray[2]=3;

w przypadku wektorów wystarczy to zadeklarować i dodać elementy

vector<int> myVector;
myVector.push_back(1);
myVector.push_back(2);
myVector.push_back(3);
...

czasami nie będziesz znać liczby potrzebnych elementów, więc wektor byłby idealny w takiej sytuacji.

Nicolas Brown
źródło