2012-05-30 19 views
7

He estado recibiendo mi cabeza redonda C++ durante unos meses, y ha sido dirigido por google para desbordar la mayor parte del tiempo para consultas C++. Anoté con frecuencia exhortaciones del tipo "¿por qué no usas un vector?", Y me inspiré para hacer exactamente eso.vectores C++ no como matrices

Por lo tanto, principalmente para obtener los beneficios menores de la desasignación de memoria automática, y poder escribir funciones de comparación tipeadas para la clasificación. Cambié una serie de punteros a objetos para que fueran un vector. Ahora pensé (incorrectamente parece) que vectores podrían utilizarse más o menos como matrices, y por lo tanto me inicializado así:

cluster clusters[LOTS]; 
vector<cluster *> pclust; 
pclust.reserve(numClust); 
for (int i=0; i<numClust; ++i) 
    pclust[i] = clusters + i; 

No hay quejas de que el compilador. Luego, algún tiempo después, debo ordenar el vector en algún atributo del objeto del clúster. Entonces:

std::sort(pclust.begin(), pclust.end(), ClusterCompareNumSegs); 

De nuevo no hay problemas para compilar. Excepto que el vector no se ordena . Resulta que vector.size() es cero, y por supuesto mi inicialización debería haber sido

pclust.push_back(clusters + i); 

Ahora que es fácil de solucionar, pero estoy confundida, porque el asignación incorrecta inicial estaba funcionando. Me iterado con éxito a través el vector - utilizando la sintaxis de matrices, así:

for (clustind=0; clustind < numClust; ++clustind) {<br> 
    cluster *cl = pclust[clustind]; 
    ...happily access *cl... 

Y todo funcionó bien. Entonces me pregunto qué está pasando. Presumiblemente en mis asignaciones iniciales, estaba tratando de acceder a los elementos que aún no están en el vector (estaba tratando de ponerlos), y el vector arrojaba excepciones que estaba ignorando. Pero, no obstante, al hacer referencia a las ubicaciones, los punteros estaban allí. ¿Alguien puede proporcionar la iluminación?

+2

La biblioteca estándar es muy amplia, y no especialmente acogedor para el principiante, le sugiero que lea la documentación sobre al menos los tipos de contenedores (http://en.cppreference.com/w/cpp) - se te salvará mucho dolor – cmannett85

+0

Solo para reiterar, mi código está todo arreglado ahora, pero me preguntaba – bandjalong

+0

... Si alguien puede explicar mientras el operador [] funcionó tan bien como lo hizo, incluso sin cambiar el tamaño. ¿Suerte con la implementación del compilador (gcc) de vectores quizás? – bandjalong

Respuesta

11

vector::reserve no cambia el tamaño de su vector, todavía contiene solo los elementos 0 con los que se creó. Lo que hace es asegurarse de que el vector puede contener numClust sin tener que reasignarlo. Ver here.

Lo que queremos es que sea para declarar un vector de tener ese tamaño

vector<cluster *> pclust(numClust); 

o para resize the vector

pclust.resize(numClust); 
+0

La razón por la que llamé reserva fue porque sabía cuántos elementos iba a agregar, y quería que hubiera suficiente espacio para que las reasignaciones no fueran necesarias al agregarlas (realmente quiero la eficiencia de las matrices, y los vectores de pensamiento estaban cerca) suficiente). – bandjalong

+0

.. Pero ¿estás diciendo que el redimensionamiento de llamadas me hubiera permitido inicializarlas con la sintaxis de la matriz? Si es así, eso es bueno (tenía miedo de que la sintaxis de la matriz no se pudiera usar como un lvalue, lo cual sería molesto). Pero todavía me pregunto por qué se inicializó la matriz, porque los datos estaban allí, pero aún no se inicializaron porque el vector pensó que tenía un tamaño cero ... – bandjalong

+0

@ user1425406: 'operador []' no agrega elementos a un vector Devuelve una referencia a los elementos existentes. 'resize()' agrega elementos a un vector. Tenga cuidado con la palabra "inicializar". En C++ tiene un significado muy específico, y para los tipos de clase que significa llamar a un constructor. 'a [3] = b' llama al operador de asignación, y eso requiere un objeto ya inicializado en la mano izquierda. – MSalters

5

std::vector::reservepeticiones que la capacidad del espacio de almacenamiento asignado a los elementos de la el contenedor vectorial debe ser al menos suficiente para contener n elementos. No cambia el tamaño del vector, eso es lo que hace std::vector::resize.

Reemplace pclust.reserve(numClust); con pclust.resize(numClust);.

Como alternativa, podría eliminar la llamada pclust.reserve(numClust); y cambiar la construcción de este vector a: vector<cluster *> pclust(numClust);, que produce el mismo resultado.

También sugerimos que al echar un vistazo a esta pregunta: std::vector reserve() and push_back() is faster than resize() and array index, why? :)

+0

Reemplazar la reserva con el cambio de tamaño no resolvería el objetivo (creo) de asegurar que se asigna exactamente el derecho de cantidad de memoria y no más (que es lo que tenía en mente, así como evitar los reallocs). Y no puedo llamar al constructor con el tamaño, porque no sé el tamaño en el momento en que se llama al constructor. Pero eso está bien, todo está bien ahora, simplemente no entiendo por qué mi código (incorrecto) funcionó tan bien como lo hizo. – bandjalong

+0

@ user1425406: ¿Por qué 'resize' asigna más memoria que' reserve'? La diferencia entre estos dos es que el redimensionamiento no solo "reserva" la memoria, sino que también construye estos elementos, por lo que puede acceder a ellos utilizando 'at()' o '[]'. Si el rendimiento es lo que estás buscando, entonces quédate con 'reserve' +' push_back'. – LihO

+0

Pensé que la reserva tenía la garantía de no asignar más que la cantidad especificada, y que el cambio de tamaño no lo era. Pero mirando ahora, no puedo ver por qué pensé eso. Así que está bien, el tamaño funcionaría (pero como sugieres, reservar y push_back es el más rápido). Básicamente, quiero que el compilador genere el mismo código que si hiciera el bucle obvio para inicializar una matriz. – bandjalong

0

operador [] se utiliza con referencia a los rendimientos de vectores elemento sobre el índice de posición. PERO, no has inicializado el vector con ningún valor, por lo que estaba vacío.

Aunque hizo un pclust.reserve(numClust), pero solo dice que el tamaño del vector cambiará pronto y asigna espacio de almacenamiento sin cambiar el tamaño del vector todavía.

+0

Pero ese es el misterio, [] estaba funcionando (después de una moda), todos esos valores iniciales que puse (mientras que el vector permaneció en el tamaño cero), se recuperaron con éxito y se desreferenciaron posteriormente. – bandjalong

0
cluster clusters[LOTS]; 
vector<cluster *> pclust(numClust); 
for (int i = 0; i < numClust; ++i) 
    pclust[i] = clusters + i; 

Pero esto significa que todavía está utilizando una matriz para almacenar clusters. ¿No puedes hacer que clusters sea un vector?

vector<cluster> clusters(LOTS); 
+0

Sí, podría, pero no puedo ver una ventaja de que sea un vector (no puedo ordenarlo de todos modos, necesito serializar estructuras de datos con indicios en él ...). – bandjalong

Cuestiones relacionadas