Usando matrices o std :: vectors en C ++, ¿cuál es la brecha de rendimiento?

208

En nuestro curso de C ++ sugieren que ya no se usen matrices de C ++ en proyectos nuevos. Hasta donde yo sé, el propio Stroustroup sugiere no utilizar matrices. ¿Pero hay diferencias de rendimiento significativas?

Tunnuz
fuente
2
¿Por qué crees que hay una brecha de rendimiento?
Martin York
99
Porque generalmente con una mejor funcionalidad viene el peor rendimiento.
tunnuz
19
Estoy de acuerdo con la optimización prematura, pero elegir el mejor método de almacenamiento por adelantado tiene mucho sentido. A menudo, en el mundo real, el código debe enviarse y el siguiente producto desarrollado y el paso de optimización nunca sucede.
hormiga
132
Ojalá la gente dejara de gritar "¡optimización prematura!" cuando alguien hace una pregunta simple relacionada con el rendimiento! responda la pregunta y no asuma PREMATURAMENTE que las personas están haciendo algo prematuramente.
d7samurai
44
@ d7samaurai: de acuerdo, aún no he visto a nadie intentar usarloint main(int argc, const std::vector<string>& argv)
Mark K Cowan

Respuestas:

189

newSe debe evitar el uso de matrices C ++ con (es decir, el uso de matrices dinámicas). Existe el problema de que debe realizar un seguimiento del tamaño, y debe eliminarlos manualmente y hacer todo tipo de limpieza.

También se desaconseja el uso de matrices en la pila porque no tiene verificación de rango, y al pasar la matriz se perderá cualquier información sobre su tamaño (conversión de matriz a puntero). Deberías usarboost::array en ese caso, que envuelve una matriz C ++ en una clase pequeña y proporciona una sizefunción e iteradores para iterar sobre ella.

Ahora las matrices std :: vector vs. C ++ nativas (tomadas de internet):

// Comparison of assembly code generated for basic indexing, dereferencing, 
// and increment operations on vectors and arrays/pointers.

// Assembly code was generated by gcc 4.1.0 invoked with  g++ -O3 -S  on a 
// x86_64-suse-linux machine.

#include <vector>

struct S
{
  int padding;

  std::vector<int> v;
  int * p;
  std::vector<int>::iterator i;
};

int pointer_index (S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int vector_index (S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusion: Indexing a vector is the same damn thing as indexing a pointer.

int pointer_deref (S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int iterator_deref (S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusion: Dereferencing a vector iterator is the same damn thing 
// as dereferencing a pointer.

void pointer_increment (S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void iterator_increment (S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusion: Incrementing a vector iterator is the same damn thing as 
// incrementing a pointer.

Nota: Si asigna matrices con newy asigna objetos que no son de clase (como simples int) o clases sin un constructor definido por el usuario y no desea que sus elementos se inicialicen inicialmente, el uso de newmatrices asignadas puede tener ventajas de rendimiento porque std::vectorinicializa todos los elementos para valores predeterminados (0 para int, por ejemplo) en construcción (créditos a @bernie por recordármelo).

Johannes Schaub - litb
fuente
77
¿Quién inventó la maldita sintaxis de AT&T? Solo si supiera ... :)
Mehrdad Afshari
44
Esto no es cierto para el compilador de Visual C ++. Pero para GCC lo es.
toto
55
El punto en mi respuesta es que el vector no tiene que ser más lento que las operaciones de puntero correspondientes. Por supuesto, puede ser (fácil de lograr al habilitar también el modo de depuración) :)
Johannes Schaub - litb
18
+1 para "Indexar un vector es lo mismo que indexar un puntero". y para las otras conclusiones también.
Nawaz
3
@ Piotr99 No voy a discutir contigo, pero cuando aprendes ensamblaje después de aprender idiomas de nivel superior, la sintaxis de Intel tiene mucho más sentido que algunos al revés, prefijos (números), sufijos (instrucciones) y oscuros (memoria de acceso ) naturaleza de la sintaxis de AT&T.
Cole Johnson
73

Preámbulo para personas con micro optimizadores

Recuerda:

"Los programadores pierden enormes cantidades de tiempo pensando o preocupándose por la velocidad de las partes no críticas de sus programas, y estos intentos de eficiencia en realidad tienen un fuerte impacto negativo cuando se consideran la depuración y el mantenimiento. Deberíamos olvidarnos de pequeñas eficiencias, digamos acerca de 97% del tiempo: la optimización prematura es la raíz de todo mal. Sin embargo, no debemos dejar pasar nuestras oportunidades en ese crítico 3% ".

(Gracias a la metamorfosis por la cotización completa)

No use una matriz C en lugar de un vector (o lo que sea) solo porque cree que es más rápido, ya que se supone que es de nivel inferior. Estarías equivocado

Use el vector predeterminado (o el contenedor seguro adaptado a sus necesidades) y luego, si su generador de perfiles dice que es un problema, vea si puede optimizarlo, ya sea utilizando un algoritmo mejor o cambiando el contenedor.

Dicho esto, podemos volver a la pregunta original.

Matriz estática / dinámica?

Las clases de matriz C ++ se comportan mejor que la matriz C de bajo nivel porque saben mucho sobre sí mismas y pueden responder preguntas que las matrices C no pueden. Son capaces de limpiar por sí mismos. Y lo que es más importante, generalmente se escriben usando plantillas y / o en línea, lo que significa que lo que parece una gran cantidad de código en la depuración se resuelve con poco o ningún código producido en la versión de lanzamiento, lo que significa que no hay diferencia con su competencia menos segura incorporada.

En general, se divide en dos categorías:

Matrices dinámicas

Usar un puntero a una matriz malloc-ed / new-ed será, en el mejor de los casos, tan rápido como la versión std :: vector, y mucho menos seguro (ver la publicación de litb ).

Entonces use un std :: vector.

Matrices estáticas

Usar una matriz estática será, en el mejor de los casos:

  • tan rápido como el std :: array versión
  • y mucho menos seguro

Entonces use un std :: array .

Memoria no inicializada

A veces, el uso vectorde un búfer en lugar de un búfer sin procesar incurre en un costo visible porque vectorinicializará el búfer en la construcción, mientras que el código que reemplaza no lo hizo, como señaló bernie en su respuesta .

Si este es el caso, puede manejarlo usando un en unique_ptrlugar de un vectoro, si el caso no es excepcional en su línea de código, escriba una clase buffer_ownerque posea esa memoria y le brinde un acceso fácil y seguro, incluyendo bonos como cambiar el tamaño ( realloc¿ usando ?), o lo que necesites.

paercebal
fuente
1
Gracias por abordar también las matrices estáticas: std :: vector es inútil si no se le permite asignar memoria dinámicamente por razones de rendimiento.
Tom
10
Cuando dices "Usar una matriz estática será, en el mejor de los casos, tan rápido como la versión boost :: array", muestra cuán sesgado eres. Debería ser al revés, Boost: array puede ser, en el mejor de los casos, rápido como arreglos estáticos.
toto
3
@toto: es un malentendido: debería leerlo como "Usar una matriz estática será, en el mejor de los casos ((tan rápido como la versión boost :: array) && (mucho menos seguro))". Editaré la publicación para aclarar esto. Por cierto, gracias por el beneficio de la duda.
paercebal
1
¿Qué pasa con std :: array?
Paul 05 de
44
Siempre muestre la cotización completa. "Los programadores pierden enormes cantidades de tiempo pensando o preocupándose por la velocidad de las partes no críticas de sus programas, y estos intentos de eficiencia en realidad tienen un fuerte impacto negativo cuando se consideran la depuración y el mantenimiento. Debemos olvidar las pequeñas eficiencias, digamos acerca de 97% del tiempo: la optimización prematura es la raíz de todo mal. Sin embargo, no debemos dejar pasar nuestras oportunidades en ese crítico 3% ". De lo contrario se convierte en una mordida sonora sin sentido.
metamorfosis
32

Los vectores son matrices debajo del capó. El rendimiento es el mismo.

Un lugar donde puede encontrarse con un problema de rendimiento, para empezar, no es dimensionar el vector correctamente.

A medida que se llena un vector, se redimensionará, y eso puede implicar, una nueva asignación de matriz, seguida de n constructores de copia, seguidos de aproximadamente n llamadas destructoras, seguido de una eliminación de matriz.

Si su construcción / destrucción es costosa, es mucho mejor hacer que el vector tenga el tamaño correcto para empezar.

Hay una manera simple de demostrar esto. Cree una clase simple que muestre cuándo se construye / destruye / copia / asigna. Cree un vector de estas cosas y comience a empujarlas en el extremo posterior del vector. Cuando el vector se llena, habrá una cascada de actividad a medida que el vector cambia de tamaño. Luego, inténtelo nuevamente con el tamaño del vector al número esperado de elementos. Verás la diferencia.

EvilTeach
fuente
44
Pendantry: el rendimiento tiene el mismo gran O. std :: vector hace un poco de contabilidad, lo que presumiblemente cuesta una pequeña cantidad de tiempo. OTOH, terminas haciendo la misma contabilidad cuando haces rodar tus propias matrices dinámicas.
dmckee --- ex-gatito moderador
si entiendo. Sin embargo, la idea central de su pregunta era cuáles son las diferencias de rendimiento ... Intenté abordar eso.
EvilTeach
El std :: vector de Gcc aumenta la capacidad uno por uno si llama a push_back.
bjhend
3
@bjhend ¿Entonces gcc's std::vectorno cumple con los estándares? Creo que el estándar requiere que vector::push_backhaya amortizado la complejidad constante, y aumentar la capacidad en 1 en cada uno push_backserá n ^ 2 complejidad después de tener en cuenta las reasignaciones. - suponiendo algún tipo de aumento exponencial de la capacidad push_backy insert, en caso de reserveno producirse, como máximo, un aumento constante del factor en las copias de contenido vectorial. Un factor de crecimiento vectorial exponencial de 1.5 significaría ~ 3 veces más copias si no lo hiciera reserve().
Yakk - Adam Nevraumont
3
@bjhend te equivocas. El estándar prohíbe el crecimiento exponencial: § 23.2.3 párrafo 16 dice "La Tabla 101 enumera las operaciones que se proporcionan para algunos tipos de contenedores de secuencia pero no para otros. Una implementación proporcionará estas operaciones para todos los tipos de contenedor que se muestran en la columna" contenedor ", y los implementará de manera tal que tome tiempo constante amortizado ". (la tabla 101 es la que contiene push_back). Ahora, por favor, deja de difundir FUD. Ninguna implementación convencional viola este requisito. La biblioteca estándar de C ++ de Microsoft crece con un factor 1.5x, y GCC crece con un factor 2x.
R. Martinho Fernandes
27

Para responder a algo, Mehrdad dijo:

Sin embargo, puede haber casos en los que aún necesite matrices. Al interactuar con código de bajo nivel (es decir, ensamblado) o bibliotecas antiguas que requieren matrices, es posible que no pueda usar vectores.

No es cierto del todo. Los vectores se degradan muy bien en matrices / punteros si usa:

vector<double> vector;
vector.push_back(42);

double *array = &(*vector.begin());

// pass the array to whatever low-level code you have

Esto funciona para todas las principales implementaciones de STL. En el próximo estándar, será necesario que funcione (aunque hoy en día funciona bien).

Frank Krueger
fuente
1
El estándar actual no dice tal cosa. Está implícito y se implementa como almacenamiento continuo. Pero el estándar simplemente dice que es un contenedor de acceso aleatorio (que usa iteradores). El siguiente estándar será explícito.
Frank Krueger
1
& * v.begin () simplemente aplica el operador & al resultado de desreferenciar el iterador. La desreferenciación puede devolver CUALQUIER tipo. El uso de la dirección del operador puede volver a devolver CUALQUIER tipo. El estándar no define esto como un puntero en un área contigua de memoria.
Frank Krueger
15
El texto original de 1998 de la Norma de hecho no lo requería, pero hubo una adición en 2003 que aborda esto, por lo que está realmente cubierto por la Norma. hierbasutter.wordpress.com/2008/04/07/…
Nemanja Trifunovic
2
C ++ 03 dice explícitamente que &v[n] == &v[0] + nes válido siempre que nesté dentro del rango de tamaño. El párrafo que contiene esta declaración no cambió con C ++ 11.
bjhend
2
¿Por qué no usar std :: vector :: data ()?
Paul 05 de
15

Tiene incluso menos razones para usar matrices simples en C ++ 11.

Hay 3 tipos de matrices en la naturaleza, de la más rápida a la más lenta, dependiendo de las características que tengan (por supuesto, la calidad de la implementación puede hacer que las cosas sean realmente rápidas incluso para el caso 3 de la lista):

  1. Estático con tamaño conocido en tiempo de compilación. ---std::array<T, N>
  2. Dinámico con tamaño conocido en tiempo de ejecución y nunca redimensionado. La optimización típica aquí es que si la matriz se puede asignar directamente en la pila. - No disponible . Tal vez dynarrayen C ++ TS después de C ++ 14. En C hay VLA
  3. Dinámico y redimensionable en tiempo de ejecución. ---std::vector<T>

Para 1. matrices estáticas simples con un número fijo de elementos, use std::array<T, N>en C ++ 11.

Para 2. matrices de tamaño fijo especificadas en tiempo de ejecución, pero eso no cambiará su tamaño, hay discusión en C ++ 14 pero finalmente se ha movido a una especificación técnica y finalmente se ha hecho de C ++ 14.

Para 3. std::vector<T> generalmente pedirá memoria en el montón . Esto podría tener consecuencias de rendimiento, aunque podría utilizarlo std::vector<T, MyAlloc<T>>para mejorar la situación con un asignador personalizado. La ventaja en comparación con T mytype[] = new MyType[n];es que puede cambiar su tamaño y que no se descompondrá en un puntero, como lo hacen las matrices simples.

Utilice los tipos de biblioteca estándar mencionados para evitar que las matrices se descompongan en punteros . Ahorrará tiempo de depuración y el rendimiento es exactamente el mismo que con las matrices simples si usa el mismo conjunto de características.

Germán Diago
fuente
2
std :: dynarray. Después de revisar los comentarios de los organismos nacionales a n3690, este componente de la biblioteca fue eliminado del documento de trabajo de C ++ 14 en una especificación técnica separada. Este contenedor no forma parte del borrador de C ++ 14 a partir de n3797. de en.cppreference.com/w/cpp/container/dynarray
Mohamed El-Nakib
1
Muy buena respuesta. breve y resumido, pero con más detalles que ninguno.
Mohamed El-Nakib
6

Ir con STL. No hay penalización de rendimiento. Los algoritmos son muy eficientes y hacen un buen trabajo al manejar los tipos de detalles en los que la mayoría de nosotros no pensaríamos.

John D. Cook
fuente
5

STL es una biblioteca muy optimizada. De hecho, incluso se sugiere usar STL en juegos en los que podría ser necesario un alto rendimiento. Las matrices son demasiado propensas a errores para ser utilizadas en las tareas diarias. Los compiladores de hoy también son muy inteligentes y realmente pueden producir código excelente con STL. Si sabe lo que está haciendo, STL generalmente puede proporcionar el rendimiento necesario. Por ejemplo, inicializando los vectores al tamaño requerido (si lo sabe desde el principio), básicamente puede lograr el rendimiento de la matriz. Sin embargo, puede haber casos en los que aún necesite matrices. Al interactuar con código de bajo nivel (es decir, ensamblado) o bibliotecas antiguas que requieren matrices, es posible que no pueda usar vectores.

Mehrdad Afshari
fuente
44
dado que el vector es contiguo, sigue siendo bastante fácil interactuar con bibliotecas que requieren matrices.
Greg Rogers
Sí, pero si desea meterse con las cosas internas del vector, habría menos ventajas en el uso de un vector. Por cierto, la palabra clave era "podría no".
Mehrdad Afshari
3
solo conozco un caso en el que los vectores no se pueden usar: si el tamaño es 0. entonces & a [0] o & * a.begin () no funcionarán. c ++ 1x lo arreglará con la introducción de una función a.data () que devuelve el búfer interno manteniendo los elementos
Johannes Schaub - litb
El escenario específico en mi mente cuando escribí que era arreglos basados ​​en pila.
Mehrdad Afshari
1
Vector de interfaz o cualquier contenedor contiguo con C: vec.data()para datos y vec.size()para tamaño. Es fácil.
Germán Diago
5

Sobre la contribución de duli .

La conclusión es que las matrices de enteros son más rápidas que los vectores de enteros (5 veces en mi ejemplo). Sin embargo, las matrices y los vectores tienen aproximadamente la misma velocidad para datos más complejos / no alineados.

lalebarde
fuente
3

Si compila el software en modo de depuración, muchos compiladores no integrarán las funciones de acceso del vector. Esto hará que la implementación del vector stl sea mucho más lenta en circunstancias donde el rendimiento es un problema. También facilitará la depuración del código, ya que puede ver en el depurador la cantidad de memoria asignada.

En modo optimizado, esperaría que el vector stl se acercara a la eficiencia de una matriz. Esto se debe a que muchos de los métodos vectoriales ahora están en línea.


fuente
Es importante mencionar esto. Perfilar cosas STL de depuración es muy, muy lento. Y es una de las razones por las cuales las personas consideran que el STL es lento.
Erik Aronesty
3

Definitivamente, hay un impacto en el rendimiento al usar una std::vectormatriz sin formato vs cuando se desea un búfer sin inicializar (por ejemplo, para usar como destino memcpy()). An std::vectorinicializará todos sus elementos utilizando el constructor predeterminado. Una matriz cruda no lo hará.

La especificación de c ++ para el std:vectorconstructor que toma un countargumento (es la tercera forma) establece:

`Construye un nuevo contenedor a partir de una variedad de fuentes de datos, opcionalmente usando un asignador asignado por el usuario.

3) Construye el contenedor con el recuento de instancias insertadas por defecto de T. No se realizan copias.

Complejidad

2-3) Lineal en conteo

Una matriz en bruto no incurre en este costo de inicialización.

Consulte también ¿Cómo puedo evitar std :: vector <> para inicializar todos sus elementos?

bernie
fuente
2

La diferencia de rendimiento entre los dos depende en gran medida de la implementación: si compara un std :: vector mal implementado con una implementación de matriz óptima, la matriz ganaría, pero la daría la vuelta y el vector ganaría ...

Siempre que compare manzanas con manzanas (tanto la matriz como el vector tienen un número fijo de elementos, o ambos cambian de tamaño dinámicamente), creo que la diferencia de rendimiento es insignificante siempre que siga la práctica de codificación STL. No olvide que el uso de contenedores C ++ estándar también le permite utilizar los algoritmos pre-enrollados que forman parte de la biblioteca C ++ estándar y es probable que la mayoría de ellos tengan un mejor rendimiento que la implementación promedio del mismo algoritmo que usted mismo construye. .

Dicho esto, en mi humilde opinión, el vector gana en un escenario de depuración con un STL de depuración, ya que la mayoría de las implementaciones de STL con un modo de depuración adecuado pueden al menos resaltar / cathc los errores típicos cometidos por las personas cuando trabajan con contenedores estándar.

Ah, y no olvide que la matriz y el vector comparten el mismo diseño de memoria, por lo que puede usar vectores para pasar datos al código C o C ++ heredado que espera matrices básicas. Sin embargo, tenga en cuenta que la mayoría de las apuestas están apagadas en ese escenario, y está lidiando con la memoria cruda nuevamente.

Timo Geusch
fuente
1
Creo que para cumplir con los requisitos de rendimiento (búsquedas e inserciones de O (1)), casi tiene que implementar std :: vector <> utilizando matrices dinámicas. Ciertamente, esta es la forma obvia de hacerlo.
dmckee --- ex-gatito moderador
No solo los requisitos de rendimiento, sino también el requisito de almacenamiento contiguo. Una mala implementación de vectores pondrá demasiadas capas de indirección entre la matriz y la API. Una implementación buen vector permitirá código inline, SIMD utilizarse en bucles, etc.
Max Lybbert
Una implementación de vector incorrecta como se describe no sería compatible con el estándar. Si desea indirección, std::dequepodría ser utilizado.
Phil1970
1

Si no necesita ajustar dinámicamente el tamaño, tiene la sobrecarga de memoria de guardar la capacidad (un puntero / size_t). Eso es.

Greg Rogers
fuente
1

Puede haber algún caso marginal en el que tenga un acceso vectorial dentro de una función en línea dentro de una función en línea, donde haya ido más allá de lo que el compilador se alineará y forzará una llamada a la función. Sería tan raro que no valiera la pena preocuparse; en general, estaría de acuerdo con litb .

Me sorprende que nadie haya mencionado esto todavía: no se preocupe por el rendimiento hasta que se haya demostrado que es un problema, luego hágalo como punto de referencia.

Mark Ransom
fuente
1

Yo diría que la principal preocupación no es el rendimiento, sino la seguridad. Puede cometer muchos errores con las matrices (considere cambiar el tamaño, por ejemplo), donde un vector le ahorraría mucho dolor.

Gabriel Isenberg
fuente
1

Los vectores usan un poquito más de memoria que las matrices, ya que contienen el tamaño de la matriz. También aumentan el tamaño del disco duro de los programas y probablemente la huella de memoria de los programas. Estos aumentos son pequeños, pero pueden ser importantes si está trabajando con un sistema integrado. Aunque la mayoría de los lugares donde importan estas diferencias son lugares donde usaría C en lugar de C ++.

Brian
fuente
2
Si esto es importante, entonces obviamente no está utilizando matrices de tamaño dinámico, y como tal, sus matrices no necesitan cambiar de tamaño. (Si lo hicieran, estaría almacenando el tamaño de alguna manera). Por lo tanto, también podría usar boost :: array a menos que me equivoque, y ¿qué le hace decir que eso necesita "almacenar el tamaño" en alguna parte?
Arafangion
1

La siguiente prueba simple:

Explicación de la prueba de rendimiento de C ++ Array vs Vector

contradice las conclusiones de "Comparación del código de ensamblaje generado para operaciones básicas de indexación, desreferenciación e incremento en vectores y matrices / punteros".

Debe haber una diferencia entre las matrices y los vectores. La prueba lo dice ... solo pruébalo, el código está ahí ...

Hamed100101
fuente
1

A veces, las matrices son mejores que los vectores. Si siempre está manipulando un conjunto de objetos de longitud fija, las matrices son mejores. Considere los siguientes fragmentos de código:

int main() {
int v[3];
v[0]=1; v[1]=2;v[2]=3;
int sum;
int starttime=time(NULL);
cout << starttime << endl;
for (int i=0;i<50000;i++)
for (int j=0;j<10000;j++) {
X x(v);
sum+=x.first();
}
int endtime=time(NULL);
cout << endtime << endl;
cout << endtime - starttime << endl;

}

donde la versión vectorial de X es

class X {
vector<int> vec;
public:
X(const vector<int>& v) {vec = v;}
int first() { return vec[0];}
};

y la versión de matriz de X es:

class X {
int f[3];

public:
X(int a[]) {f[0]=a[0]; f[1]=a[1];f[2]=a[2];}
int first() { return f[0];}
};

La versión de matriz de main () será más rápida porque estamos evitando la sobrecarga de "nuevo" cada vez en el bucle interno.

(Este código fue publicado en comp.lang.c ++ por mí).

duli
fuente
1

Si está utilizando vectores para representar un comportamiento multidimensional, hay un impacto en el rendimiento.

¿Los vectores 2d + causan un impacto en el rendimiento?

La esencia es que hay una pequeña cantidad de sobrecarga con cada sub-vector que tiene información de tamaño, y no necesariamente habrá serialización de datos (como ocurre con las matrices c multidimensionales). Esta falta de serialización puede ofrecer mayores oportunidades de micro optimización. Si está haciendo arreglos multidimensionales, puede ser mejor simplemente extender std :: vector y rodar su propia función get / set / resize bits.

Seph Reed
fuente
0

Suponiendo una matriz de longitud fija (p. Ej. , int* v = new int[1000];Vs std::vector<int> v(1000);, con el tamaño de vmantenerse fijo en 1000), la única consideración de rendimiento que realmente importa (o al menos me importó cuando estaba en un dilema similar) es la velocidad de acceso a un elemento. Busqué el código vectorial de STL, y esto es lo que encontré:

const_reference
operator[](size_type __n) const
{ return *(this->_M_impl._M_start + __n); }

Esta función seguramente será incorporada por el compilador. Por lo tanto, siempre que lo único que planee hacer vsea ​​acceder a sus elementos operator[], parece que realmente no debería haber ninguna diferencia en el rendimiento.

Subh_b
fuente