Quel est le capacity()
d'un std::vector
créé à l'aide du constituant par défaut? Je sais que size()
est zéro. Pouvons-nous affirmer qu'un vecteur construit par défaut n'appelle pas l'allocation de mémoire en tas?
De cette façon, il serait possible de créer un tableau avec une réserve arbitraire en utilisant une seule allocation, telle que std::vector<int> iv; iv.reserve(2345);
. Disons que pour une raison quelconque, je ne veux pas commencer le size()
à 2345.
Par exemple, sous Linux (g ++ 4.4.5, noyau 2.6.32 AMD64)
#include <iostream>
#include <vector>
int main()
{
using namespace std;
cout << vector<int>().capacity() << "," << vector<int>(10).capacity() << endl;
return 0;
}
imprimé 0,10
. Est-ce une règle ou dépend-il du fournisseur STL?
La norme ne spécifie pas ce que la capacity
initiale d'un conteneur devrait être, vous vous fiez donc à la mise en œuvre. Une mise en œuvre commune démarrera la capacité à zéro, mais il n'y a aucune garantie. En revanche, il n’ya aucun moyen d’améliorer votre stratégie de std::vector<int> iv; iv.reserve(2345);
, alors tenez-vous-en à cela.
Les implémentations de stockage de std :: vector varient de manière significative, mais toutes celles que j'ai rencontrées commencent à 0.
Le code suivant:
#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;
}
Donne le résultat suivant:
0
1
2
4
4
8
8
8
8
16
16
sous GCC 5.1 et:
0
1
2
3
4
6
6
9
9
9
13
sous MSVC 2013.
Pour compléter légèrement les autres réponses, j’ai constaté que lorsqu’il est exécuté dans des conditions de débogage avec Visual Studio, un vecteur construit par défaut reste alloué sur le segment de mémoire même si sa capacité commence à zéro.
Spécifiquement si _ITERATOR_DEBUG_LEVEL! = 0 alors vector, allouera de l’espace pour faciliter la vérification des itérateurs.
https://docs.Microsoft.com/en-gb/cpp/standard-library/iterator-debug-level
Je viens de trouver cela légèrement gênant puisque j’utilisais un allocateur personnalisé à l’époque et que je n’attendais pas l’allocation supplémentaire.
Pour autant que j'ai compris la norme (bien que je ne puisse pas réellement nommer de référence), l'instanciation de conteneur et l'allocation de mémoire ont été délibérément découplées pour une bonne raison. Par conséquent, vous avez des appels distincts, séparés pour
constructor
pour créer le conteneur lui-mêmereserve()
pour allouer préalablement un bloc de mémoire suffisamment volumineux pour accueillir au moins (!) un nombre donné d'objetsEt cela a beaucoup de sens. Le seul droit à exister pour reserve()
est de vous donner la possibilité de coder des réallocations éventuellement coûteuses lors de la croissance du vecteur. Pour être utile, vous devez connaître le nombre d'objets à stocker ou au moins être capable de faire une supposition éclairée. Si cela ne vous est pas donné, évitez plutôt reserve()
car vous ne ferez que modifier la réallocation pour le gaspillage de mémoire.
Donc, tout mettre ensemble:
reserve()
et ce dernier n’a pas besoin de se trouver au même endroit de construction (peut/devrait bien sûr être plus tard, une fois que vous avez pris connaissance de la taille requise pour accueillir)reserve()
, n'est-ce pas?Push_back()
- s'il n'a pas déjà été explicitement alloué auparavant par reserve()
.Tout cela ne fonctionne pleinement et n’est avantageux que s’il n’est pas perturbé par un constructeur qui alloue. Vous avez des valeurs par défaut raisonnables pour les scénarios courants qui peuvent être remplacés à la demande par reserve()
(et shrink_to_fit()
). Donc, même si le standard ne le dit pas explicitement, je suis tout à fait sûr de supposer qu'un vecteur nouvellement construit ne préalloue pas est un pari relativement sûr pour toutes les implémentations actuelles.
Standard ne spécifie pas la valeur initiale de la capacité, mais le conteneur STL s'adapte automatiquement au nombre de données que vous avez inséré, à condition de ne pas dépasser la taille maximale (utilisez la fonction membre max_size à connaître) . est gérée par realloc chaque fois que plus d'espace est requis. Supposons que vous souhaitiez créer un vecteur contenant une valeur de 1 000 à 1 000. Sans utiliser de réserve, le code entraînera généralement entre 2 et 18 réallocations lors de la boucle suivante:
vector<int> v;
for ( int i = 1; i <= 1000; i++) v.Push_back(i);
Modifier le code pour utiliser la réserve peut entraîner 0 affectation pendant la boucle:
vector<int> v;
v.reserve(1000);
for ( int i = 1; i <= 1000; i++) v.Push_back(i);
En gros, les capacités de vecteur et de chaîne sont multipliées par un facteur compris entre 1,5 et 2 à chaque fois.