71 votes

Le déplacement d'un vecteur invalide-t-il les itérateurs?

Si j'ai un itérateur pour un vecteur, puis-je passer de construire ou de déplacer attribuer un autre vecteur à partir de ce vecteur, est-ce que itérateur, il reste un élément valide dans le nouveau vecteur? Voici un exemple simple:

#include <vector>
#include <iostream>

int main(int argc, char *argv[])
{
    std::vector<int>::iterator a_iter;
    std::vector<int> b;
    {
        std::vector<int> a{1, 2, 3, 4, 5};
        a_iter = a.begin() + 2;
        b = std::move(a);
    }
    std::cout << *a_iter << std::endl;
    return 0;
}

Est - a_iter valide, car a a été déplacé en b, ou est l'itérateur invalidé par la déplacer? Pour référence, std::vector::swap n'a pas pour effet d'invalider les itérateurs.

25voto

John Dibling Points 56814

Alors qu'il pourrait être raisonnable de supposer que, iterators sont toujours valables après un move, je ne pense pas que le Standard assure de fait cette. Par conséquent, les itérateurs sont dans un état indéfini après l' move.


Il n'y a pas de référence que je peux trouver dans la Norme qui précise que les itérateurs qui existait avant l' move sont toujours valables après l' move.

Sur la surface, il semble tout à fait raisonnable de supposer que l' iterator est généralement mis en œuvre comme des pointeurs dans la séquence contrôlée. Si c'est le cas, alors les itérateurs reste valide après l' move.

Mais la mise en œuvre d'un iterator est mise en œuvre définies. Sens, tant que l' iterator sur une plate-forme répond aux exigences définies par la Norme, il peut être mis en œuvre de quelque manière que ce soit. Il pourrait, en théorie, être mis en œuvre comme une combinaison d'un pointeur de retour à l' vector classe avec un index. Si c'est le cas, alors les itérateurs deviendrait invalide après l' move.

Si oui ou non un iterator est effectivement mise en œuvre de cette façon n'est pas pertinent. Il pourrait être mise en œuvre de cette façon, donc, sans une garantie spécifique de la Norme que le post-move itérateurs sont encore valide, vous ne pouvez pas supposer qu'ils sont. N'oubliez pas également qu'il y est une telle garantie pour les itérateurs après un swap. Cela a été expressément précisé à partir de la Norme précédente. C'était peut-être simplement d'un oubli de la Std comité pour ne pas faire une précision similaire pour les itérateurs après un move, mais en tout cas il n'y a aucune garantie.

Par conséquent, le long et le court de il est, vous ne pouvez pas assumer votre itérateurs sont toujours bien après une move.

EDIT:

23.2.1/11 dans le Projet de n3242 stipule que:

À moins d'indication contraire (soit explicitement, soit par la définition d'un fonction en ce qui concerne les autres fonctions), invoquant un conteneur membre la fonction ou du passage d'un conteneur comme argument à une fonction de la bibliothèque n'invalidera pas les itérateurs, ou modifier les valeurs, les objets dans ce conteneur.

Cela pourrait conduire à la conclusion que les itérateurs sont valables après un move, mais je suis en désaccord. Dans votre exemple de code, a_iter a été un itérateur à l' vector a. Après l' move, ce conteneur, a a certainement été changé. Ma conclusion est la clause ci-dessus ne s'applique pas dans ce cas.

12voto

Jerry Coffin Points 237758

Je pense que l'édition qui a changé déplacer construction de déplacer les modifications d'attributions de la réponse.

Au moins, si je suis en train de lire le tableau 96 correctement, la complexité pour se déplacer de construction est considéré comme une "note B", qui est une constante de la complexité pour rien, sauf std::array. La complexité pour se déplacer d'affectation, cependant, est donné comme linéaire.

En tant que tel, le déplacement de la construction a essentiellement pas d'autre choix que de copier le pointeur de la source, auquel cas il est difficile de voir comment les itérateurs pourrait devenir invalide.

Pour l'assignation de déplacement, cependant, la complexité linéaire signifie qu'il pourrait choisir de déplacer les différents éléments de la source à la destination, auquel cas les itérateurs sera presque certainement deviennent invalides.

La possibilité de déplacer la cession des éléments est renforcé par la description: "Tous les éléments de a sont soit déplacer affectée ou détruit". Le "détruit" la partie correspondrait à détruire le contenu existant, et de "voler" le pointeur de la source -- mais le "déplacer attribué à" indiquent le déplacement des éléments individuels de la source à la destination à la place.

4voto

Mark Ransom Points 132545

Puisqu'il n'y a rien qui empêche un itérateur de conserver une référence ou un pointeur sur le conteneur d'origine, je dirais que vous ne pouvez pas compter sur la validité des itérateurs à moins que vous ne trouviez une garantie explicite dans la norme.

-1voto

Kerrek SB Points 194696

Un itérateur vous donne accès à un élément dans un conteneur spécifique. Une fois que vous déplacez-la construction d'un nouveau conteneur à partir d'un vieux, le vieux contient pas d'éléments, et donc il n'y a pas dereferenceable des itérateurs pour l'un de ses éléments.

Imaginez que vous essayez de vérifier pour la fin du conteneur:

std::vector<Foo>::iterator it = a.begin(), e = e.end();

std::vector<Foo> b(std::move(a));

for ( ; it != a.end(); ++it) // ???
for ( ; it != b.end(); ++it) // ???
assert(a.end() == e);        // ???

Quel doit être le sens de l' ++it ? Il n'est pas logique, n'importe quelle manière vous la faire tourner. L' a itérateurs sont plus valides, et vous devez obtenir un nouveau b des itérateurs de vérifier pour la fin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X