std :: array против производительности массива


87

Если я хочу построить очень простой массив, например

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); . . . может даже не компилироваться (кажется, что временные объекты фундаментального типа неизменяемы, по крайней мере, с clang 6)
Патрик Фромберг

Инициализация тоже волшебным образом отличается: 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 с языком = C ++ 17)
BitTickler

Почему двойные скобки при std::arrayинициализации?
Marc.2377

Ответы:


102

В чем преимущества использования 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
};

Это агрегат , и он позволяет вам использовать его почти как основной тип (т.е. вы можете передавать по значению, назначать и т. Д., Тогда как стандартный массив C не может быть назначен или скопирован непосредственно в другой массив). Вам следует взглянуть на некоторую стандартную реализацию (перейти к определению из вашей любимой среды IDE или напрямую открыть <array>), это часть стандартной библиотеки C ++, которую довольно легко читать и понимать.


25

std::array разработан как оболочка с нулевыми накладными расходами для массивов C, которая придает ему «нормальное» значение, подобное семантике других контейнеров C ++.

Вы не должны замечать никакой разницы в производительности во время выполнения, пока все еще сможете пользоваться дополнительными функциями.

Использование std::arrayвместо int[]массивов стилей - хорошая идея, если у вас есть C ++ 11 или boost.


10

Он более производительный?

Должно быть точно так же. По определению, это простой агрегат, единственным членом которого является массив.

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

Я тестировал эту конкретную ситуацию на Godbolt :

#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-array дает неверный результат; 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.