2010-12-05 3 views
1

Tenir compte ce morceau de code:C++ Conteneurs STL et la validité du pointeur

Uint counter = 0; 

int* p1; 
int* p2; 

deque<int> dequeInstance; 
vector<int> vectorInstance; 

dequeInstance.push_back(3); 
dequeInstance.push_back(7); 

p1 = &dequeInstance.back(); 

dequeInstance.push_back(17); 

p2 = &dequeInstance.back(); 

if(*p1 == !7) 
    ++counter; 

if(*p2 == !17) 
    ++counter; 

vectorInstance.push_back(3); 
vectorInstance.push_back(7); 

p1 = &vectorInstance.back(); 

vectorInstance.push_back(17); 

p2 = &vectorInstance.back(); 

if(*p1 == !7) 
    ++counter; 

if(*p2 == !17) 
    ++counter; 



return counter; 

Je me serais attendu à ce que quand je poussais le troisième élément à l'arrière du vecteur, le pointeur vers le deuxième élément aurait été invalidée , comme ma compréhension de std :: vector est que c'est un tableau droit qui est effacé et recréé chaque fois qu'il est modifié. À la fin de ce code, le «compteur» est égal à zéro.

Qu'est-ce qui me manque ici?

Répondre

5

Espérons que pour les performances, std::vector n'est pas 'effacé et recréé chaque fois qu'il est modifié'.

Un vecteur a un capacity qui peut dépasser son size, ce qui signifie qu'il peut allouer plus de mémoire que réellement utilisé. Lorsque vous push_back, une réallocation ne se produira que si la nouvelle taille est supérieure à l'ancienne capacité, et dans ce cas, les itérateurs sont invalidés.

Dans votre cas, vous devez vérifier la valeur de capacity juste après l'instanciation std::vector. Vous verrez que c'est sans aucun doute supérieur à 3, donc aucun de vos appels push_back ne déclenche une réallocation et tous les itérateurs restent valables.

Notez également que std::vector fournit une fonction membre reserve qui vous permet de contrôler la capacité vectorielle. Ceci est vraiment utile lorsque vous savez combien d'éléments sont censés être insérés afin d'éviter une réaffectation ultérieure.

+1

La norme garantit un temps constant amorti pour 'push_back'. Cela signifie que 'vector' ne peut pas être redimensionné à chaque fois. L'espoir n'est pas nécessaire ici :) – fredoverflow

2

Ok, vous avez quelques problèmes. Tout d'abord,! N = 0 sauf si n = 0 et ensuite il est égal à 1. Donc le compteur ne s'incrémente jamais. Deuxièmement, un vecteur ne détruit pas nécessairement le contenu lorsque vous repoussez un nouvel élément par push_back. Un vecteur a 2 "tailles". 1 est le nombre d'éléments dans le vecteur et 2 est la quantité de mémoire allouée. Le vecteur n'est réaffecté et copié que lorsque la quantité de mémoire allouée est épuisée.

En outre, après avoir supprimé une zone de mémoire, la mémoire n'est pas nécessairement effacée et peut toujours pointer vers des données valides.

Vous n'utilisez pas d'itérateurs pour ne pas être invalidés. Vous utilisez des pointeurs et ils pointent simplement sur une zone de mémoire. Ce n'est pas parce que cette mémoire n'est pas allouée que le pointeur est invalide. C'est l'un des dangers majeurs que C/C++ peut vous laisser avec. Assurez-vous de ne pas faire ce genre de choses car vous invoquez un "comportement indéfini" qui peut faire n'importe quoi de "ne pas causer de problèmes et apparemment fonctionner" jusqu'à "planter horriblement et détruire votre système d'exploitation d'une manière dangereuse".

+0

whoops! Thats destiné à être! =. Je réécrivais ce que j'avais écrit le matin. J'ai besoin de dormir. – Tomas

+0

@Tomas: Bien que le compteur ne soit jamais incrémenté parce que le pointeur pointe toujours vers des données valides ou pointe vers la mémoire et un comportement indéfini, dans votre cas, voit que les valeurs restent en mémoire après l'allocation a été retourné au tas ... – Goz

Questions connexes