2012-09-04 15 views
63

¿Cuál es el capacity() de un std::vector que se crea utilizando el constructor predeterminado? Sé que el size() es cero. ¿Podemos decir que un vector construido por defecto no llama a la asignación de memoria de pila?Capacidad inicial de vector en C++

De esta forma, sería posible crear una matriz con una reserva arbitraria utilizando una única asignación, como std::vector<int> iv; iv.reserve(2345);. Digamos que, por alguna razón, no quiero para iniciar el size() en 2345.

Por ejemplo, en Linux (g ++ 4.4.5, 2.6.32 del núcleo AMD64)

#include <iostream> 
#include <vector> 

int main() 
{ 
    using namespace std; 
    cout << vector<int>().capacity() << "," << vector<int>(10).capacity() << endl; 
    return 0; 
} 

impresos 0,10. ¿Es una regla o depende del proveedor de STL?

+6

El estándar no especifica nada sobre la capacidad inicial del vector, pero la mayoría de las implementaciones usan 0. –

+8

No hay garantía, pero cuestionaría seriamente la calidad de cualquier implementación que asignara memoria sin que yo la solicite. –

+0

@MikeSeymour No estoy de acuerdo. Una implementación de alto rendimiento podría contener un pequeño búfer en línea, en cuyo caso establecer la capacidad inicial() tendría sentido. – alastair

Respuesta

46

La norma no especifica cuál debe ser el contenedor capacity inicial de un contenedor, por lo que confía en la implementación. Una implementación común iniciará la capacidad en cero, pero no hay garantía. Por otro lado, no hay forma de mejorar su estrategia de std::vector<int> iv; iv.reserve(2345);, así que quédese con ella.

+1

No compro tu última declaración. Si no puede confiar inicialmente en la capacidad de 0, puede reestructurar su programa para permitir que su vector tenga un tamaño inicial. Esto equivaldría a la mitad del número de solicitudes de memoria de montón (de 2 a 1). – bitmask

+4

@bitmask: Siendo práctico: ¿conoces alguna implementación * any * donde un vector asigna memoria en el constructor predeterminado? No está garantizado por el estándar, pero como Mike Seymour señala desencadenar una asignación sin la necesidad sería un mal olor con respecto a la * calidad de la implementación *. –

+2

@ DavidRodríguez-dribeas: Ese no es el punto. La premisa era "no se puede hacer mejor que tu estrategia actual, así que no te molestes en preguntarte si * podría haber * implementaciones estúpidas". Si la premisa era "no hay implementaciones de este tipo, así que no te molestes", lo compraría. La conclusión es cierta, pero la implicación no funciona. Lo siento, tal vez estoy picando liendres. – bitmask

15

implementaciones de almacenamiento de std :: vector varían significativamente, pero todos los que me he encontrado con salida desde 0.

El siguiente código:

#include <iostream> 
#include <vector> 

int main() 
{ 
    using namespace std; 

    vector<int> normal; 
    cout << normal.capacity() << endl; 

    for (unsigned int loop = 0; loop != 10; ++loop) 
    { 
     normal.push_back(1); 
     cout << normal.capacity() << endl; 
    } 

    std::cin.get(); 
    return 0; 
} 

da el siguiente resultado:

0 
1 
2 
4 
4 
8 
8 
8 
8 
16 
16 

bajo GCC 5.1 y:

0 
1 
2 
3 
4 
6 
6 
9 
9 
9 
13 

bajo MSVC 2013.

+3

Oh, bueno, fueron lo suficientemente inteligentes como para comenzar en 0. – Andrew

+2

Esto está tan subestimado @Andrew –

+0

Bueno, prácticamente en todas partes se encuentra que la recomendación para la velocidad es casi siempre usar simplemente un vector, por lo que si se está haciendo algo que involucre datos dispersos ... – Andrew

2

Como un ligero además de las otras respuestas, he encontrado que cuando se ejecuta en condiciones de depuración con Visual Studio un vector predeterminado construida todavía asignará en el montón a pesar de que la capacidad comienza en cero.

Específicamente si _ITERATOR_DEBUG_LEVEL! = 0, entonces vector asignará algo de espacio para ayudar con la comprobación del iterador.

https://docs.microsoft.com/en-gb/cpp/standard-library/iterator-debug-level

Acabo de encontrar este poco molesto, ya que estaba usando un asignador de costumbre en la época, y no estaba esperando la asignación adicional.

+0

Interesante, rompen el noexcept- garantías (al menos para C + 17, anteriormente?): http://en.cppreference.com/w/cpp/container/vector/vector – Deduplicator

0

El estándar no especifica el valor inicial de capacidad pero el contenedor STL crece automáticamente para acomodar tantos datos como usted ingresa, siempre que no exceda el tamaño máximo (use la función de miembro max_size para saber). Para vector y cadena, el crecimiento se maneja con realloc cada vez que se necesita más espacio. Supongamos que desea crear un vector que contenga el valor 1-1000. Sin el uso de la reserva, el código será típicamente resultar en entre 2 y 18 reasignaciones durante siguiente bucle:

vector<int> v; 
for (int i = 1; i <= 1000; i++) v.push_back(i); 

Modificación del código para utilizar la reserva podría resultar en 0 asignaciones durante el bucle:

vector<int> v; 
v.reserve(1000); 

for (int i = 1; i <= 1000; i++) v.push_back(i); 

Aproximadamente para decir, las capacidades de vectores y cuerdas crecen por un factor de entre 1.5 y 2 cada vez.