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 ++, которую довольно легко читать и понимать.

vsoftco
источник
25

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

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

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

Baum mit Augen
источник
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таки нужно делать копии, то все будет правильно и все равно будет иметь такую ​​же производительность.

b4hand
источник