std :: array проти продуктивності масиву


85

Якщо я хочу побудувати дуже простий масив типу

int myArray[3] = {1,2,3};

Чи слід використовувати std::arrayзамість цього?

std::array<int, 3> a = {{1, 2, 3}};

Які переваги використання std :: array перед звичайними? Це ефективніше? Просто простіше керувати копією / доступом?


2
визначення багатовимірного масиву за допомогою std :: буде важким
goGud

15
@goGud: Не складно, просто детальніше.
Майк Сеймур

1
Розпад вказівника, взяття посилання тощо ..., багато чого дивного в c-масивах. Ітератор може бути покажчиком у випадку c-масивів і for (auto i = ++std::begin(myArray); . . . може навіть не компілювати (здається, що тимчасові
принципи

Ініціалізація також чарівно відрізняється: struct Direction { int32_t dw; int32_t dh; };і static const Direction DIRECTIONS[DIRECTIONS_COUNT] { { -1, 1}, {0,1}, {1,1} , { 1, 0 }, {1,-1}, {0,-1} , {-1,-1}, {-1,0} };компілюється. Але якщо ви перейдете до того std::array<Direction,DIRECTIONS_COUNT>ж списку ініціалізаторів, раптом ви отримаєте помилку "занадто багато ініціалізаторів". (VS 2019 Community with language = C ++ 17)
BitTickler

Чому подвійні дужки в std::arrayініціалізації?
Марк.2377

Відповіді:


101

Які переваги використання std::arrayперед звичайними?

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

Це ефективніше?

Це повинно бути точно так само. За визначенням, це простий агрегат, що містить масив як єдиний його член.

Просто простіше впоратися з копіюванням / доступом?

Так.


41

A std::array- це дуже тонка обгортка навколо масиву в стилі C, що в основному визначається як

template<typename T, size_t N>
class array
{
public:
    T _data[N];
    T& operator[](size_t);
    const T& operator[](size_t) const;
    // other member functions and typedefs
};

Це сукупність , і вона дозволяє використовувати його майже як основний тип (тобто ви можете передавати значення, призначати тощо, тоді як стандартний масив С не можна призначити або скопіювати безпосередньо в інший масив). Вам слід поглянути на якусь стандартну реалізацію (перейти до визначення з вашої улюбленої IDE або безпосередньо відкрити <array>), це частина стандартної бібліотеки C ++, яку досить легко читати і розуміти.


24

std::array розроблений як обгортка з нульовими накладними витратами для масивів C, що надає йому "нормальне" значення, як семантика інших контейнерів C ++.

Ви не повинні помічати жодної різниці у швидкодії, поки ви все одно насолоджуєтеся додатковими функціями.

Використання std::arrayзамість int[]масивів стилів - хороша ідея, якщо під рукою є C ++ 11 або boost.


10

Це ефективніше?

Це повинно бути точно так само. За визначенням, це простий агрегат, що містить масив як єдиний його член.

Ситуація видається більш складною, оскільки std::arrayне завжди виробляється однаковий код збірки порівняно з C-масивом, залежно від конкретної платформи.

Я протестував цю конкретну ситуацію на болті :

#include <array>
void test(double* const C, const double* const A,
          const double* const B, const size_t size) {
  for (size_t i = 0; i < size; i++) {
    //double arr[2] = {0.e0};//
    std::array<double, 2> arr = {0.e0};//different to double arr[2] for some compiler
    for (size_t j = 0; j < size; j++) {
      arr[0] += A[i] * B[j];
      arr[1] += A[j] * B[i];
    }
    C[i] += arr[0];
    C[i] += arr[1];
  }
}

GCC і Clang виробляють однаковий код збірки як для версії C-масиву, так і дляstd::array версії.

Однак MSVC та ICPC видають різні коди збірки для кожної версії масиву. (Я тестував ICPC19 за допомогою -Ofastта -Os; MSVC -Oxта -Os)

Я поняття не маю, чому це так (я б справді очікував абсолютно однакової поведінки std :: array та c-array). Можливо, використовуються різні стратегії оптимізації.

Як трохи додаткового: здається, в ICPC є помилка з

#pragma simd 

для векторизації при використанні c-масиву в деяких ситуаціях (код c-масиву видає неправильний результат; std::arrayверсія працює нормально).

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

Я подам звіт про помилки в Intel, коли буду впевнений, що я не просто щось неправильно зрозумів щодо C-array / std::arrayі #pragma simd.


1
можна розглядати як помилку компілятора?
OznOg

8

std::arrayмає значення семантики, тоді як необроблені масиви - ні. Це означає, що ви можете скопіюватиstd::array та розглядати це як примітивне значення. Ви можете отримати їх за значенням або посиланням як аргументи функції, а можете повернути за значенням.

Якщо ви ніколи не копіюєте a std::array, тоді різниці в продуктивності немає, ніж необроблений масив. Якщо вам потрібно зробити копії, тоді std::arrayви зробите правильно, і все одно повинні мати однакову продуктивність.

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