2009-05-11 21 views
75

Mi pregunta es simple: ¿los elementos std :: vector están garantizados para ser contiguos? En orden palabra, ¿puedo usar el puntero al primer elemento de std :: vector como C-array?¿Están garantizados los elementos std :: vector contiguos?

Si mi memoria me sirve, el estándar C++ no garantiza tanto. Sin embargo, los requisitos de std :: vector eran tales que era prácticamente imposible cumplirlos si los elementos no eran contiguos.

¿Alguien puede aclarar esto?

Ejemplo:

std::vector<int> values; 
// ... fill up values 

if(!values.empty()) 
{ 
    int *array = &values[0]; 
    for(int i = 0; i < values.size(); ++i) 
    { 
     int v = array[i]; 
     // do something with 'v' 
    } 
} 
+0

Sé que estás en problemas si mutate 'values' dentro de ese bloque' if'. No sé la respuesta a tu pregunta, así que dejo un comentario. :) –

+0

@Greg: ¿Qué problema? ¿Puedes elaborar un poco? – Reunanen

+0

Supongo que quiso decir que presionar nuevos valores puede desencadenar un "realloc" que haría que la matriz se volviera inválida. –

Respuesta

80

Esto se omitió desde el estándar C++ 98 propiamente dicho, pero luego se agregó como parte de un TR. El próximo estándar C++ 0x por supuesto lo incluirá como un requisito.

De n2798 (proyecto de C++ 0x):

23.2.6 plantilla de clase vector [vector]

1 Un vector es un contenedor de secuencias que soporta iteradores de acceso aleatorio. Además, admite (amortizado) operaciones de inserción y borrado de tiempo constante al final; insertar y borrar en el medio toma tiempo lineal. La administración del almacenamiento se maneja automáticamente, aunque se pueden dar pistas para mejorar la eficiencia. Los elementos de un vector se almacenan contiguamente, lo que significa que si v es un vector donde T es algún otro tipo que bool, entonces obedece a la identidad & v [n] == & v [0] + n para todos 0 < = n < v.size().

+3

Esto también se indica en la norma ISO 14882, segunda Edición: Sección 23.2.4 [lib.vector]: "Los elementos de un vector se almacenan de forma contigua, lo que significa que si v es un vector donde T es un tipo distinto de bool, entonces obedece a la identidad & v [n] == & v [0] + n para todos 0 <= n

+3

so s, TR, TC, :) En realidad C++ 03 también se llama C++ 98-TC1 (corrigendum técnico) por lo que leo –

+0

@litb: Correcto. Sigo olvidando cuál es cuál. – dirkgently

2

Sí, los elementos de un std :: vector están garantizados para ser contiguos.

+0

Derecha. Supongo que uso demasiados :) –

6

El estándar de hecho garantiza que un vector es continuo en la memoria y que &a[0] se puede pasar a una función C que espera una matriz.

La excepción a esta regla es vector<bool> que sólo utiliza un bit por lo tanto bool aunque tiene memoria continua no puede ser utilizado como un bool* (esto es ampliamente considerado como una falsa optimización y un error).

Por cierto, ¿por qué no usa iteradores? Para eso están para.

+1

> Por cierto, ¿por qué no usas iteradores? Para eso están para. Tal vez leyó el nuevo artículo de Alexanrescu sobre el tema: http://www.boostcon.com/site-media/var/sphene/sphwiki/attachment/2009/05/08/iterators-must-go.pdf –

+0

Gracias para el enlace, voy a mi lista de lectura (trato de no perderme los artículos de Alexandresu) – Motti

+0

Mwahaha, todos parecen estar hablando de esa presentación en estos días. Mira, la discusión todavía está caliente al respecto: http://groups.google.com/group/comp.lang.c++.moderado/browse_thread/thread/9b74808d7d869060 –

1

cplusplus.com:

contenedores vector se implementan como matrices dinámicas; Al igual que las matrices normales, los contenedores vectoriales tienen sus elementos almacenados en ubicaciones de almacenamiento contiguas, lo que significa que se puede acceder a sus elementos no solo utilizando iteradores sino también utilizando compensaciones en punteros regulares a los elementos.

12

Como han señalado otras respuestas, se garantiza que el contenido de un vector será continuo (exceptuando la rareza de bool).

El comentario que quería agregar es que si realiza una inserción o una eliminación en el vector, lo que podría hacer que el vector reasigne su memoria, hará que todos sus punteros e iteradores guardados se invaliden. .

+1

Los elementos aún se almacenarían en un bloque de memoria contiguo, simplemente estaría en un lugar diferente. La pregunta era específicamente sobre la contigüidad. – Dima

+2

Pero los punteros y los iteradores existentes quedarían invalidados. –

+0

Buen punto. Debe poner eso en su respuesta para aclarar lo que quiere decir. – Dima

5

Como ya se ha dicho, vector utiliza internamente una matriz contigua de objetos. Los punteros en esa matriz deben tratarse como no válidos siempre que cualquier función miembro no const se llame IIRC.

Sin embargo, hay una excepción!

vector<bool> tiene una implementación especializada diseñada para ahorrar espacio, por lo que cada bool solo usa un bit. La matriz subyacente no es una matriz contigua de bool y la aritmética de matriz en vector<bool> no funciona como vector<T>.

(supongo que también es posible que esto sea cierto para cualquier especialización de vectores, ya que siempre podemos implementar uno nuevo. Sin embargo, std::vector<bool> es la única especialización estándar sobre la cual la aritmética de punteros simples no funcionará .)

+0

El usuario no puede especializar '' std :: vector'', y todos los demás vectores son requerido para usar el almacenamiento contiguo. Por lo tanto, '' std :: vector '' es (afortunadamente) el único vector estándar que es raro. (Soy de la opinión de que esta especialización debe ser obsoleta y reemplazada por ej. Un '' std :: dynamic_bitset'' con la misma funcionalidad. No es una estructura de datos mala, simplemente no es un vector.) –

3

Encontré este hilo porque tengo un caso de uso donde los vectores que usan memoria contigua son una ventaja.

Estoy aprendiendo a usar objetos de búfer de vértice en OpenGL. Creé una clase contenedora para contener la lógica del buffer, así que todo lo que necesito hacer es pasar una matriz de flotantes y algunos valores de configuración para crear el buffer. Quiero poder generar un búfer desde una función basada en la entrada del usuario, por lo que no se conoce la longitud en tiempo de compilación. Hacer algo como esto sería la solución más fácil:

void generate(std::vector<float> v) 
{ 
    float f = generate_next_float(); 
    v.push_back(f); 
} 

Ahora puede pasar flotadores del vector como una matriz de funciones relacionadas con el búfer de OpenGL. Esto también elimina la necesidad de sizeof para determinar la longitud de la matriz.

Esto es mucho mejor que asignar una gran matriz para almacenar los flotadores y esperar que sea lo suficientemente grande, o hacer mi propia matriz dinámica con almacenamiento contiguo.

+1

esta función no tiene ningún sentido para mí. ¿Quieres pasar una referencia o un puntero a 'v' en lugar de a' v' en sí? porque pasar 'v' solo hará que se realice una copia dentro de la función, que dejará de existir después de que la función termine. Por lo tanto, estás presionando algo sobre el vector solo para eliminar el vector cuando finaliza la función. – johnbakers

Cuestiones relacionadas