std :: matriz vs rendimiento de matriz

84

Si quiero construir una matriz muy simple como

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

¿Debería usar std::arrayen su lugar?

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

¿Cuáles son las ventajas de usar std :: array sobre los habituales? ¿Es más eficaz? ¿Simplemente más fácil de manejar para copiar / acceder?

Arcyno
fuente
2
definir una matriz multidimensional con std :: será difícil
goGud
15
@goGud: No es difícil, solo más detallado.
Mike Seymour
1
Decaimiento del puntero, tomando una referencia, etc., muchas cosas son extrañas acerca de las matrices c. El iterador puede ser un puntero en el caso de c-arrays y es for (auto i = ++std::begin(myArray); . . . posible que ni siquiera se compile (parece que los temporales de tipo fundamental no son mutables, al menos no con clang 6)
Patrick Fromberg
La inicialización también difiere mágicamente: struct Direction { int32_t dw; int32_t dh; };y static const Direction DIRECTIONS[DIRECTIONS_COUNT] { { -1, 1}, {0,1}, {1,1} , { 1, 0 }, {1,-1}, {0,-1} , {-1,-1}, {-1,0} };compila. Pero si cambia a una std::array<Direction,DIRECTIONS_COUNT>con la misma lista de inicializadores, de repente aparece el error "demasiados inicializadores". (Comunidad VS 2019 con lenguaje = C ++ 17)
BitTickler
¿Por qué los corchetes dobles en la std::arrayinicialización?
Marc.2377

Respuestas:

101

¿Cuáles son las ventajas de usar std::arraysobre los habituales?

Tiene una semántica de valor amigable, de modo que se puede pasar o devolver de funciones por valor. Su interfaz hace que sea más conveniente encontrar el tamaño y usarlo con algoritmos basados ​​en iteradores de estilo STL.

¿Es más eficaz?

Debería ser exactamente igual. Por definición, es un agregado simple que contiene una matriz como único miembro.

¿Simplemente más fácil de manejar para copiar / acceder?

Si.

Mike Seymour
fuente
41

A std::arrayes una envoltura muy delgada alrededor de una matriz de estilo C, básicamente definida como

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

Es un agregado y le permite usarlo casi como un tipo fundamental (es decir, puede pasar por valor, asignar, etc., mientras que una matriz C estándar no se puede asignar o copiar directamente a otra matriz). Debería echar un vistazo a alguna implementación estándar (saltar a la definición de su IDE favorito o abrir directamente <array>), es una parte de la biblioteca estándar de C ++ que es bastante fácil de leer y comprender.

vsoftco
fuente
24

std::array está diseñado como contenedor de cero sobrecarga para matrices C que le da el valor "normal" como la semántica de los otros contenedores de C ++.

No debería notar ninguna diferencia en el rendimiento en tiempo de ejecución mientras aún disfruta de las funciones adicionales.

Usar en std::arraylugar de int[]matrices de estilo es una buena idea si tiene C ++ 11 o boost a mano.

Baum mit Augen
fuente
10

¿Es más eficaz?

Debería ser exactamente igual. Por definición, es un agregado simple que contiene una matriz como único miembro.

La situación parece ser más complicada, ya std::arrayque no siempre produce un código ensamblador idéntico en comparación con C-array dependiendo de la plataforma específica.

Probé esta situación específica en 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 y Clang producen un código ensamblador idéntico tanto para la versión C-array como para la std::arrayversión.

Sin embargo, MSVC e ICPC producen un código de ensamblaje diferente para cada versión de la matriz. (Probé ICPC19 con -Ofasty -Os; MSVC -Oxy -Os)

No tengo idea de por qué este es el caso (de hecho, esperaría un comportamiento exactamente idéntico de std :: array y c-array). Quizás se empleen diferentes estrategias de optimización.

Como un pequeño extra: parece haber un error en ICPC con

#pragma simd 

para la vectorización cuando se usa la matriz c en algunas situaciones (el código de la matriz c produce una salida incorrecta; la std::arrayversión funciona bien).

Desafortunadamente, todavía no tengo un ejemplo de trabajo mínimo para eso, ya que descubrí ese problema mientras optimizaba un fragmento de código bastante complicado.

Presentaré un informe de error a intel cuando esté seguro de que no entendí mal algo sobre C-array / std::arrayy #pragma simd.

Henryk
fuente
1
se puede considerar como un error del compilador?
OznOg
8

std::arraytiene semántica de valor, mientras que las matrices en bruto no. Esto significa que puede copiarlo std::arrayy tratarlo como un valor primitivo. Puede recibirlos por valor o referencia como argumentos de función y puede devolverlos por valor.

Si nunca copia a std::array, entonces no hay diferencia de rendimiento que una matriz sin formato. Si necesita hacer copias, entonces std::arrayhará lo correcto y aún así debería ofrecer el mismo rendimiento.

b4hand
fuente