comment est push_back mis en œuvre dans le vecteur STL?
J'ai été demandé à cette question dans une interview.
Les points que j'ai répondu sont comme ça
1) un index indiquant la position actuelle;
2) redimensionner si nécessaire.
Quelqu'un peut-il donner plus de détails?
La question était de savoir spécifiques de mise en œuvre? Toutes les implémentations sont autorisés à être différent.
La réponse est "c'est de la mise en œuvre définies". Sérieusement, stupides questions de l'entrevue devrait être sanctionnée par un grand nombre de coups sur la tête par un cluebat...
Je pense que c'est les programmeurs qui ne peut pas écrire un vecteur doit être puni. Nous avons tous les deux un point (et une chauve-souris).
pourquoi les entreprises devraient-elles être puni pour montrer la façon dont beaucoup qu'ils font ou ne savent pas à propos de C++ et de la STL? Semble que l'information est bon d'avoir.
Semble que l'employeur avait une chance de s'échapper.
La réponse est "c'est de la mise en œuvre définies". Sérieusement, stupides questions de l'entrevue devrait être sanctionnée par un grand nombre de coups sur la tête par un cluebat...
Je pense que c'est les programmeurs qui ne peut pas écrire un vecteur doit être puni. Nous avons tous les deux un point (et une chauve-souris).
pourquoi les entreprises devraient-elles être puni pour montrer la façon dont beaucoup qu'ils font ou ne savent pas à propos de C++ et de la STL? Semble que l'information est bon d'avoir.
Semble que l'employeur avait une chance de s'échapper.
OriginalL'auteur skydoor | 2010-04-12
Vous devez vous connecter pour publier un commentaire.
STL
vector
a untaille
(le nombre d'éléments stockés) et uncapacité
(actuellement à l'espace de stockage alloué).size < capacity
, unpush_back
met tout simplement le nouvel élément à la fin et incrémente lesize
par 1.size == capacity
avant lapush_back
, un nouveau, plus grand tableau est alloué (deux fois la taille est commun, mais c'est dépendant de l'implémentation autant que je sache), toutes les données sont copiées (y compris le nouvel élément), et l'ancien espace alloué est libéré. Ce peut lancer une exception si l'allocation échoue.La complexité de l'opération est amorti O(1), ce qui signifie que lors d'une
push_back
qui provoque un redimensionner, ce ne sera pas une constante de temps de l'opération (mais en général, au cours de nombreuses opérations, il est).k
fois plus grand que l'ancien. Il est également à noter que, pour unek
, chaque élément est copié1/(k-1)
fois en moyenne (pourk=2
c'est juste une copie supplémentaire).+1 pour l'amortissement de la perspicacité.
Aussi,
2
n'est pas le facteur le plus commun. La plupart des implémentations ont changé le nombre d'or parce qu'il joue plus agréable avec de la mémoire... ce sujet a été discuté ici et une SORTE de comp.lang.c++.animé thread a été référencée.Ah, ne le savais pas. Merci pour l'info; pouvez-vous fournir des liens vers les discussions que vous mentionnez?
OriginalL'auteur tzaman
void std::vector<T>::push_back
?Merci. Je savais que j'allais gâcher...
Parfaite réponse à une mauvaise question. Techniquement correcte, sans répondre à ce qu'ils signifie pour demander.
Peut-être que je suis dense, mais je ne suis pas sûr de ce que d'autre n'était prévu. Je pense que demandé: "Comment est push_back mis en œuvre dans
std::vector
?" J'aurais donné cette réponse dans l'interview.Je suppose qu'ils sont à la recherche d'une réponse impliquant la gestion de la mémoire (comme tzaman de réponse).
OriginalL'auteur sbi
Que, bien sûr, est naturellement de mise en œuvre définies. En supposant que c'est une question de savoir comment quelqu'un peut mettre en œuvre un tableau dynamique, en général, ce serait quelque chose comme ceci:
push_back
vérifiecapacity()
et s'assure qu'elle est au moins l'un plus grand quesize()
.Certains STL implémentations d'éluder une partie des copies en utilisant des swaps (c'est à dire pour les conteneurs des conteneurs), mais pour la plupart, c'est exactement la façon dont il fonctionne.
OriginalL'auteur Billy ONeal
Éventuellement ce qu'ils cherchaient, c'est que
push_back
fait une copie de l'objet qui est poussé sur lavector
(à l'aide de son constructeur de copie).À l'égard de redimensionnement: que dit La norme
a.push_back(x)
est équivalent àa.insert(a.end(),x)
. La définition deinsert
dit, en partie: “les Causes de réaffectation si la nouvelle taille est plus grande que l'ancienne.”Que dit la norme ce les fonctions sont censés faire. Mais la façon dont ils sont mis en œuvre est, dans la plupart des cas, la mise en œuvre spécifique.
OriginalL'auteur Nate
vector
ne pas utiliser une liste chaînée. Il utilise de la mémoire continue.Si il n'y a pas assez d'espace réservé
push_back
alloue un nouveau bloc de mémoire deux fois aussi grand que l'originalvector
. Ce faisant, l'amorti d'exécution est O(1).étrange. Pour un facteur de 1,5 à deux exemplaires pour chaque éléments est en moyenne sont nécessaires, alors que pour le facteur 2, c'est juste 1 copie.
Andrew Koenig a écrit un article il y a des années sur une raison de favoriser un plus petit facteur. Avec un facteur de deux, la somme des morceaux que vous avez jetés sera toujours plus petite que votre prochaine grande répartition, de sorte que vous n'arrivez pas à les réutiliser pour le même conteneur. Aussi longtemps que le facteur est <=le nombre d'or, ils vont éventuellement ajouter jusqu'à un assez grand morceau afin de les réutiliser pour les prochaines part plus importante des ressources.
c'est le cas seulement si le sous-jacent gestionnaire de mémoire alloue les morceaux thriftily. Toutefois, le gestionnaire peut s'en tenir à 2^n morceaux qui rend le 1.5-schéma inutile.
OriginalL'auteur Axel Gneiting
Grâce à certains commentaires, je suis tout à fait de la révision d'un très incorrecte réponse originale à cette question.
Selon la STL spec, votre réponse est correcte. Le vecteur est mis en œuvre comme un redimensionné dynamiquement tableau:
Le sous-jacentes de la mémoire tampon d'un vecteur doivent être contiguës, ce qui signifie qu'il ne peut pas être une liste liée. Le push_back() la méthode peut toujours s'exécuter en temps constant (en moyenne) si le redimensionnement ne se produit pas lors de chaque appel. Cela nécessite généralement que le tampon de l'augmentation de la taille par un facteur (par exemple, le double de taille chaque fois que le vecteur est plein).
OriginalL'auteur
Comment beaucoup de détails ne l'interviewer voulez? Par exemple, il était à la recherche pour vous de percer vers le bas le niveau de détails?
En plus de l'habituel redimensionner-comme-nécessaire de conserver le O(1) sur la moyenne de la sémantique, certaines choses à considérer incluent, mais ne sont pas limités à:
vector
's allocateur de la place de la plaine de vieuxnew
en fonction de l'allocateur (les deux peuvent ou peuvent ne pas être les mêmes)? Idéalement, cela sera géré de manière transparente par levector
'redimensionnement de code, de mise en œuvre pourrait certainement être différente, cependant.OriginalL'auteur Void
Comme suit:
OriginalL'auteur Crazy Eddie
Si la taille des < capasity, alors que tout semble être ok, vous venez d'insérer fr élément dans le vecteur, la complexité accures lorsque la taille de l' == capasity.
Il est facile de explaint sur les mots que vous devez allouer un nouveau tableau deux fois plus grand que celui existant et copie de tous ces éléments dans de nouveaux alocated de mémoire et après supprimer l'ancien et insérer le nouvel élément dans le tableau. Mais voici quelques moments clés que je considère votre interlocuteur attend de vous que vous mentionnez.
Les éléments de std::vector ne sont pas conservées dans un tableau, de sorte que le membre de données de std::vector[1000] n'est pas un int* de longueur 1000. Les éléments sont conservés dans des blocs de mémoire, donc vous devez prendre en compte lors de la copie.
Deuxièmement, la norme de vecteur stl exige "donnez-moi un copiable objet et je peux insérer", ce qui signifie que requierment sur std::vector est que sometype seul a avoir un copy_constructer (pas l'opérateur = ). Ainsi, lorsque vous êtes alocating une nouvelle mémoire de type sometype, vous devez prendre en compte que sometyme ne peut pas avoir un constructeur de copie par défaut. En commun des implémentations, ce qui est fait par le placement nouvel opérateur pour éviter l'appel de la copie des constructeurs.
OriginalL'auteur Eduard Rostomyan