Pointeurs vers des éléments de std::vector et std::list

J'ai un std::vector avec des éléments d'une classe ClassA. De plus, je veux créer un index en utilisant un std::map<key,ClassA*> qui mappe une valeur de clé à des pointeurs vers des éléments contenus dans le vecteur.

Y a-t-il une garantie que ces pointeurs restent valides (et pointent vers le même objet) lorsque des éléments sont ajoutés à la fin du vecteur (pas inséré). I. e, le code suivant correcte:

std::vector<ClassA> storage;
std::map<int, ClassA*> map;

for (int i=0; i<10000; ++i) {
  storage.push_back(ClassA());
  map.insert(std::make_pair(storage.back().getKey(), &(storage.back()));
}
// map contains only valid pointers to the 'correct' elements of storage

Quelle est la situation, si j'utilise std::list au lieu de std::vector?

29
demandé sur MartinStettner 2010-07-20 11:23:47

7 réponses

Vecteurs-Non. Comme la capacité des vecteurs ne se rétrécit jamais, il est garanti que les références, les pointeurs et les itérateurs restent valides même lorsque les éléments sont supprimés ou modifiés, à condition qu'ils se réfèrent à une position avant les éléments manipulés. Toutefois, les insertions peuvent invalider les références, les pointeurs et les itérateurs.

Listes-Oui, l'insertion et la suppression d'éléments n'invalide pas les pointeurs, les références et les itérateurs vers d'autres éléments

25
répondu DumbCoder 2010-07-20 07:30:38

Pour autant que je sache, il n'y a pas une telle garantie. L'ajout d'éléments au vecteur entraînera une réallocation des éléments, invalidant ainsi tous vos pointeurs dans la carte.

9
répondu SadSido 2010-07-20 07:28:28

Utiliser std::deque! Les pointeurs vers les éléments sont stables lorsque seul push_back() est utilisé.

Note: les itérateurs d'éléments peuvent être invalidés! Les pointeurs vers les éléments ne le seront pas.

Edit: cette réponse explique les détails pourquoi: l'itérateur de C++ deque invalidé après push_front()

6
répondu Sjoerd 2017-05-23 11:47:12

Je ne suis pas sûr que ce soit garanti, mais en pratique storage.reserve(needed_size) devrait s'assurer qu'aucune réallocation ne se produit.

Mais pourquoi ne stockez-vous pas les index?
Il est facile de convertir des index en itérateurs en les ajoutant à l'itérateur begin (storage.begin()+idx) et il est facile de transformer n'importe quel itérateur en pointeur en le déréférençant d'abord, puis en prenant son adresse (&*(storage.begin()+idx)).

3
répondu sbi 2010-07-20 07:56:52

Faites-leur simplement les deux pointeurs de magasin et supprimez explicitement les objets lorsque vous n'en avez pas besoin.

std::vector<ClassA*> storage;
std::map<int, ClassA*> map;

for (int i=0; i<10000; ++i) {
  ClassA* a = new ClassA()
  storage.push_back(a)
  map.insert(std::make_pair(a->getKey(), a))
}
// map contains only valid pointers to the 'correct' elements of storage
1
répondu Tom 2010-07-20 07:37:11

D'un des commentaires à une autre réponse, il semble que tout ce que vous voulez est de centraliser (faciliter) la gestion de la mémoire. Si c'est vraiment le cas, vous devriez envisager d'utiliser des solutions préemballées comme la bibliothèque Boost pointer container et garder votre propre code aussi simple que possible.

En particulier, jetez un oeil à ptr_map

1
répondu David Rodríguez - dribeas 2010-07-20 08:35:17
  1. pour les vecteurs no.
  2. Pour les listes Oui. comment? itérateur fonctionne comme un pointeur sur un nœud particulier dans la liste. vous pouvez donc attribuer des valeurs à n'importe quelle structure comme:

    Liste maliste;

    Paire de temp;

    Temp = make_pair( maliste.begin (), x);

0
répondu Nakul Vaidya 2017-12-20 17:11:25