2009-07-10 19 views
25

¿Hay alguna manera de reducir la capacidad de un vector?reducir la capacidad de un vector stl

Mi código inserta valores en un vector (sin conocer su número de antemano), y cuando esto finaliza, los vectores se usan solo para operaciones de lectura.

Creo que podría crear un nuevo vector, hacer un .reseve() con el tamaño y copiar los elementos, pero realmente no me gusta la operación de copia adicional.

PD: No me importa una solución portátil, siempre y cuando funcione para gcc.

+4

Sólo una nota, de reserva() no necesariamente se reserva la cantidad exacta que se pasa a ella; reserva una cantidad mayor o igual que la cantidad que pasa a reservar(). – DeadHead

+1

Tenga en cuenta que la expresión de intercambio realiza una copia. No sé si GCC tiene una extensión para liberar la memoria reservada no utilizada. En mi opinión, tal método debería estar en el estándar para vector <>. –

+4

Considera usar una deque en lugar de vector. Es casi tan rápido como el vector, pero no guarda los datos en bloques contiguos y no necesita reserva() – Wacek

Respuesta

37
std::vector<T>(v).swap(v); 

Intercambio del contenido con otro vector intercambia la capacidad.

std::vector<T>(v).swap(v); ==> is equivalent to 

std::vector<T> tmp(v); // copy elements into a temporary vector 
     v.swap(tmp);    // swap internal vector data 

Cambiar() solo cambiaría la estructura de datos interna.

+2

Sí, esto es esencialmente una copia. AFAIK esta es la única forma estándar de hacer lo que el OP quiere. En cuanto a una forma no estándar que evita la copia (que el OP consideraría aceptable), no estoy seguro de si el STL de GCC tiene esto (pero no me sorprendería que lo haga). –

+0

Michael, dudo que esté garantizado por el estándar para funcionar. – avakar

+3

@avakar - sí, esto está garantizado para funcionar según el estándar (ver el desglose de lo que está sucediendo). pero también está garantizado para copiar todos los elementos del vector original. –

6

La solución idiomática es cambiar con un vector de nueva construcción.

vector<int>().swap(v); 

Editar: He leído mal la pregunta. El código anterior borrará el vector. OP quiere mantener los elementos intactos, solo encoge capacity() a size().

Es difícil decir si el código de AJ hará eso. Dudo que haya una solución portátil. Para gcc, tendrá que echar un vistazo a su implementación particular de vector.

edit: Así que he echado un vistazo a la implementación libstdC++. Parece que la solución de AJ sí funcionará.

vector<int>(v).swap(v); 

Ver the source, línea 232.

+1

Nota: esto libera la memoria para el vector, pero también elimina * todos * los elementos (ya que está intercambiando con un vector temporal vacío). –

13

ir a buscar a punto STL Scott Meyers eficaz 17.

Básicamente no se puede reducir directamente el tamaño de almacenamiento de un std :: vector. Cambiar el tamaño y reseverar nunca reducirá la huella de memoria de un contenedor. El "truco" es crear un nuevo contenedor del tamaño correcto, copiar los datos e intercambiarlos con el contenedor actual. Si desea borrar un recipiente a cabo esto es simplemente:

std::vector<T>().swap(v); 

Si tenemos que copiar los datos a través de entonces tenemos que hacer la copia:

std::vector<T>(v).swap(v); 

Lo que esto hace es crea una nueva vector con los datos del anterior, haciendo la copia que se requeriría en cualquier operación que tenga el efecto que necesita. Luego, al llamar a swap, simplemente intercambiará los búferes internos entre los objetos. Al final de la línea, se elimina el vector temporal que se creó, pero tiene las agallas del vector anterior y el vector anterior tiene las agallas de la nueva copia que es el tamaño exacto que necesitamos.

2

No digo que GCC no podría tener algún método para hacer lo que quiere sin una copia, pero sería complicado de implementar (creo) porque los vectores necesitan usar un objeto Allocator para asignar y desasignar memoria , y la interfaz para un Allocator no incluye un método reallocate().No creo que sea imposible, pero podría ser complicado.

+0

Creo que sería imposible para el contenedor vectorial, ya que se requiere que los elementos sean contiguos en la memoria. No me he dado cuenta de que los asignadores solo tienen .allocate() y .deallocate(), así que supongo que este es el motivo por el que dicha funcionalidad no existe. – ynimous

+1

La función realloc() es fácil en C, pero cuando empiezas a agregar más semántica a la asignación de memoria se vuelve más complicado. Creo que es por eso que no hay contraparte en C++. –

3

No, no puede reducir la capacidad de un vector sin copiar. Sin embargo, puede controlar la cantidad de crecimiento de la asignación nueva verificando capacity() y call reserve() cada vez que inserta algo. El comportamiento predeterminado para std :: vector es aumentar su capacidad en un factor de 2 cada vez que se necesita una nueva capacidad. Puede crecimiento que por su propia relación de la magia:

template <typename T> 
void myPushBack(std::vector<T>& vec, const T& val) { 
    if (vac.size() + 1 == vac.capacity()) { 
     vac.reserve(vac.size() * my_magic_ratio); 
    } 

    vec.push_back(val); 
} 

Si usted está en un poco hacky técnicas, puede pasar siempre en su propio asignador y hacer lo que hay que hacer para recuperar la capacidad no utilizada.

31

Con C++ 11, puede llamar a la función de miembro shrink_to_fit(). La sección 23.2.6.2 draft standard dice:

shrink_to_fit es una solicitud no vinculante para reducir capacity() a size(). [Nota: la solicitud no es vinculante para permitir latitud para optimizaciones específicas de la implementación. -fin nota]

1

Si usted está preocupado acerca de la sobrecarga de su vector entonces tal vez debería estar buscando a utilizar otro tipo de estructura de datos. Mencionaste que una vez que tu código termina de inicializar el vector, se convierte en un proceso de solo lectura. Sugeriría ir con una matriz abierta que permita al programa decidir su capacidad en tiempo de compilación. O tal vez una lista vinculada sería más adecuada a sus necesidades.
Dime si entendí por completo lo que estabas tratando de decir.

-UBcse

+0

Otras estructuras de datos tienen más sobrecarga en caso de que tenga muy pocos elementos. Si tengo un caso donde necesito millones de contenedores. std :: vector necesita significativamente menos memoria en este caso. –

0

Obtener el "STL eficaz" libro de Scott Myers. Tiene un jus de elemento completo sobre la reducción de la capacidad del vector.

Cuestiones relacionadas