std :: array vs wydajność tablicy

87

Jeśli chcę zbudować bardzo prostą tablicę, taką jak

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

Powinienem użyć std::arrayzamiast tego?

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

Jakie są zalety używania std :: array nad zwykłymi? Czy jest bardziej wydajny? Po prostu łatwiejsze w obsłudze do kopiowania / dostępu?

Arcyno
źródło
2
zdefiniowanie wielowymiarowej tablicy za pomocą std :: będzie trudne
goGud
15
@goGud: Nie jest trudne, tylko bardziej szczegółowe.
Mike Seymour
1
Zanik wskaźnika, pobieranie referencji itp ..., wiele rzeczy jest dziwnych w c-tablicach. Iterator może być wskaźnikiem w przypadku c-arrays i for (auto i = ++std::begin(myArray); . . . może nawet się nie kompilować (wydaje się, że elementy tymczasowe typu podstawowego nie są zmienne, przynajmniej nie z clang 6)
Patrick Fromberg
Inicjalizacja również różni się magicznie: struct Direction { int32_t dw; int32_t dh; };i static const Direction DIRECTIONS[DIRECTIONS_COUNT] { { -1, 1}, {0,1}, {1,1} , { 1, 0 }, {1,-1}, {0,-1} , {-1,-1}, {-1,0} };kompiluje. Ale jeśli zmienisz na std::array<Direction,DIRECTIONS_COUNT>z tą samą listą inicjalizatorów, nagle pojawi się błąd „zbyt wiele inicjatorów”. (Społeczność VS 2019 z językiem = C ++ 17)
BitTickler
Po co podwójne nawiasy w std::arrayinicjalizacji?
Marc 2377

Odpowiedzi:

102

Jakie są zalety używania std::arraynad zwykłymi?

Ma przyjazną semantykę wartości, dzięki czemu może być przekazywany lub zwracany z funkcji przez wartość. Jego interfejs ułatwia znalezienie rozmiaru i korzystanie z algorytmów opartych na iteratorach w stylu STL.

Czy jest bardziej wydajny?

Powinien być dokładnie taki sam. Z definicji jest to prosta agregacja zawierająca tablicę jako jedyny element członkowski.

Po prostu łatwiejsze w obsłudze do kopiowania / dostępu?

Tak.

Mike Seymour
źródło
41

A std::arrayto bardzo cienkie opakowanie wokół tablicy w stylu C, zasadniczo zdefiniowane jako

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
};

Jest to agregat i pozwala na używanie go prawie jak podstawowego typu (tj. Można przekazać wartość, przypisać itp., Podczas gdy standardowej tablicy C nie można przypisać ani skopiować bezpośrednio do innej tablicy). Powinieneś rzucić okiem na jakąś standardową implementację (przeskocz do definicji ze swojego ulubionego IDE lub otwórz bezpośrednio <array>), jest to fragment standardowej biblioteki C ++, który jest dość łatwy do odczytania i zrozumienia.

vsoftco
źródło
25

std::array jest zaprojektowany jako opakowanie z zerowym narzutem dla tablic C, które nadaje mu „normalną” wartość, podobnie jak semantyka innych kontenerów C ++.

Nie powinieneś zauważyć żadnej różnicy w wydajności środowiska uruchomieniowego, podczas gdy nadal możesz cieszyć się dodatkowymi funkcjami.

Używanie tablic stylów std::arrayzamiast int[]tablic stylów jest dobrym pomysłem, jeśli masz pod ręką C ++ 11 lub boost.

Baum mit Augen
źródło
10

Czy jest bardziej wydajny?

Powinien być dokładnie taki sam. Z definicji jest to prosta agregacja zawierająca tablicę jako jedyny element członkowski.

Sytuacja wydaje się być bardziej skomplikowana, ponieważ std::arraynie zawsze tworzy identyczny kod asemblera w porównaniu z tablicą C, w zależności od konkretnej platformy.

Przetestowałem tę konkretną sytuację na 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 i Clang generują identyczny kod asemblera zarówno dla wersji C-array, jak i dla std::arraywersji.

Jednak MSVC i ICPC generują inny kod asemblera dla każdej wersji macierzy. (Testowałem ICPC19 z -Ofasti -Os; MSVC -Oxi-Os )

Nie mam pojęcia, dlaczego tak jest (rzeczywiście spodziewałbym się dokładnie identycznego zachowania std :: array i c-array). Może są stosowane różne strategie optymalizacji.

Jako mały dodatek: wygląda na to, że w ICPC jest błąd z

#pragma simd 

do wektoryzacji podczas używania tablicy c w niektórych sytuacjach (kod c-array generuje nieprawidłowe dane wyjściowe; std::arraywersja działa dobrze).

Niestety nie mam jeszcze minimalnego przykładu roboczego na to, ponieważ odkryłem ten problem podczas optymalizacji dość skomplikowanego fragmentu kodu.

Prześlę raport o błędzie do firmy Intel, gdy będę pewien, że nie tylko źle zrozumiałem coś o C-array / std::arrayi #pragma simd.

Henryk
źródło
1
można uznać za błąd kompilatora?
OznOg
8

std::arrayma semantykę wartości, podczas gdy surowe tablice nie. Oznacza to, że możesz go skopiować std::arrayi traktować jak wartość pierwotną. Możesz je otrzymać jako wartość lub odwołanie jako argumenty funkcji i możesz zwrócić je według wartości.

Jeśli nigdy nie kopiujesz std::array, nie ma różnicy w wydajności niż surowa tablica. Jeśli musisz zrobić kopie, std::arraypostąpisz właściwie i nadal powinieneś dawać taką samą wydajność.

b4hand
źródło