Масиви проти векторів: вступні подібності та відмінності [закрито]


111

Які відмінності між масивом та вектором у C ++? Прикладом відмінностей можуть бути бібліотеки, символіка, здібності тощо.

Масив

Масиви містять конкретну кількість елементів певного типу. Щоб компілятор міг резервувати необхідну кількість місця під час компіляції програми, ви повинні вказати тип та кількість елементів, які буде містити масив при його визначенні. Компілятор повинен бути в змозі визначити це значення при складанні програми. Після того, як масив визначений, ви використовуєте ідентифікатор масиву разом з індексом для доступу до конкретних елементів масиву. [...] масиви нульово індексуються; тобто перший елемент знаходиться в індексі 0. Ця схема індексації вказує на тісний взаємозв'язок у C ++ між вказівниками та масивами та правила, які мова визначає для арифметики вказівника.

- Посилання на кишеньковий C ++

Вектор

Вектор - це послідовність об'єктів з динамічним розміром, що забезпечує operator[]випадковий доступ у стилі масиву . Функція-член push_backкопіює свої аргументи через конструктор копій, додає цю копію як останній елемент у векторі та збільшує його розмір на одиницю.pop_backробить навпаки, видаляючи останній елемент. Вставлення або видалення елементів з кінця вектора вимагає амортизованого постійного часу, а вставлення або видалення з будь-якого іншого місця займає лінійний час. Це основи векторів. Їх набагато більше. У більшості випадків вектор повинен бути вашим першим вибором для масиву стилю С. Перш за все, вони мають динамічний розмір, а значить, можуть рости в міру необхідності. Вам не доведеться робити всілякі дослідження, щоб визначити оптимальний статичний розмір, як у випадку з масивами С; вектор зростає у міру необхідності, і його можна змінити в більший чи менший розмір вручну, якщо вам потрібно. По-друге, вектори пропонують перевірку меж з atфункцією члена (але не зoperator[]), так що ви можете щось робити, якщо ви посилаєтесь на неіснуючий індекс, а не просто спостерігати за тим, як ваша програма виходить з ладу або ще гірше, продовжуючи виконання з пошкодженими даними.

- Кулінарна книга C ++


Найбільш основна відмінність: є цілі, для яких вектор - хороший вибір.
Джеррі Труну

1
"вичерпний" і "консис" є ортогональними. Тобто, не тільки одне не має на увазі іншого, але вони навіть не в одному масштабі.
Гонки легкості на орбіті

2
Мене дуже засмучують люди, які закривають питання, які є саме тією інформацією, яку я шукаю. Це трапляється занадто часто.
Роберт Тамлін

Відповіді:


142

масиви:

  • - вбудована мовна конструкція;
  • приходять майже немодифіковані з C89;
  • забезпечити лише суміжну послідовність елементів, що підлягає індексуванню ; жодних дзвіночків;
  • мають фіксований розмір; ви не можете змінити розмір масиву в C ++ (якщо тільки це масив POD і не виділений з ним malloc);
  • їх розмір повинен бути константою часу компіляції, якщо вони не розподіляються динамічно;
  • вони займають місце для зберігання залежно від сфери, де ви їх заявляєте;
  • якщо динамічно розподілено, ви повинні чітко їх розмістити;
  • якщо вони динамічно розподіляються, ви просто отримуєте вказівник, і ви не можете визначити їх розмір; в іншому випадку ви можете використовувати sizeof(звідси загальну ідіому sizeof(arr)/sizeof(*arr), яка, однак, виходить з ладу при ненавмисному використанні вказівника);
  • автоматично відхиляється до покажчиків у більшості ситуацій; зокрема, це відбувається при передачі їх функції, яка зазвичай вимагає передачі окремого параметра за їх розміром;
  • не може бути повернуто з функції;
  • не можна скопіювати / призначити безпосередньо;
  • динамічні масиви об'єктів потребують конструктора за замовчуванням, оскільки всі їх елементи повинні бути побудовані спочатку;

std::vector:

  • клас шаблонів;
  • є лише конструкцією C ++;
  • реалізується як динамічний масив ;
  • динамічно росте і скорочується;
  • автоматично керувати їх пам’яттю, яка звільняється від знищення;
  • можна передавати / повертати з функцій (за значенням);
  • можна скопіювати / призначити (це виконує глибоку копію всіх збережених елементів);
  • не занепадає до покажчиків, але ви можете явно отримати вказівник на їх дані ( &vec[0]гарантовано, як працює, як очікувалося);
  • завжди приносить разом із внутрішнім динамічним масивом його розмір (скільки елементів на даний момент зберігається) та ємність (скільки елементів можна зберігати у виділеному на даний момент блоці);
  • внутрішній динамічний масив не виділяється всередині самого об’єкта (який містить лише кілька полів "бухгалтерського обліку"), а динамічно розподіляється розподільником, визначеним у відповідному параметрі шаблону; за замовчуванням отримує пам'ять з freestore (так званої купи), незалежно від того, як розподіляється фактичний об'єкт;
  • з цієї причини вони можуть бути менш ефективними, ніж "регулярні" масиви для малих, короткотривалих, локальних масивів;
  • при перерозподілі об'єкти копіюються (переміщуються, в C ++ 11);
  • не потребує конструктора за замовчуванням для об'єктів, що зберігаються;
  • краще інтегруватися з рештою так званої STL (вона забезпечує begin()/ end()методи, звичайні STL typedefs, ...)

Також розглянемо "сучасну альтернативу" масивам - std::array; Я вже описав в іншій відповіді різницю між, std::vectorі std::array, можливо, ви захочете це подивитися.


1
Дякую, @MatteoItalia. Довідка чи дві були б непогані.
Транкот

1
@Trancot: будь-яка хороша книга на C ++ зробить.
Matteo Italia

6
@Trancot: Я справді не можу дати вам кращих посилань - розбіжності, що підкреслюються в цій публікації, походять з багатьох різних частин Стандарту та їх краще розуміти за допомогою хорошого керівництва C ++.
Matteo Italia

Приклад такого обширного опису був би чудовим!
carloswm85

26

Додам, що масиви - це дуже низькі конструкції в C ++, і ви повинні намагатися якомога більше триматися подалі від них, коли "вивчаєте мотузки" - навіть Бьярн Струструп рекомендує це (він є дизайнером C ++).

Вектори дуже близькі до такої ж продуктивності, що і масиви, але з великою кількістю зручностей та функцій безпеки. Ви, ймовірно, почнете використовувати масиви, коли взаємодієте з API, які мають справу з необробленими масивами, або коли створюєте власні колекції.


1
Інтерфейс програми програми: ( en.wikipedia.org/wiki/API ). Це сукупність вхідних точок до об’єкта програмного забезпечення (пакет, бібліотека, операційна система). Деякі API матимуть точки входу, такі як strcat (char * dst, char * src), де dst та src трактуються як масиви символів (навіть якщо підпис функції передбачає покажчики на символи).
Джон Келлен

11

Ці посилання майже відповідали на ваше запитання. Простіше кажучи, довжини векторів є динамічними, тоді як масиви мають фіксований розмір. під час використання масиву ви визначаєте його розмір при оголошенні:

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

для векторів ви просто оголосите це і додаєте елементи

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

час від часу ви не знаєте кількість необхідних елементів, щоб вектор був ідеальним для такої ситуації.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.