Invalidation de std :: insert_iterator et de l’iterator

J’ai essayé d’écrire une fonction générique, en place, intersperse . La fonction doit disperser un élément donné dans une séquence d’éléments.

 #include  #include  #include  #include  template void intersperse(ForwardIterator begin, ForwardIterator end, InserterFunc ins, // we cannot use rvalue references here, // maybe taking by value and letting users feed in std::ref would be smarter const ForwardIterator::value_type& elem) { if(begin == end) return; while(++begin != end) { // bugfix would be something like: // begin = (ins(begin) = elem); // insert_iterator is convertible to a normal iterator // or // begin = (ins(begin) = elem).iterator(); // get the iterator to the last inserted element // begin now points to the inserted element and we need to // increment the iterator once again, which is safe // ++begin; ins(begin) = elem; } } int main() { typedef std::list container; // as expected tumbles, falls over and goes up in flames with: // typedef std::vector container; typedef container::iterator iterator; container v{1,2,3,4}; intersperse(v.begin(), v.end(), [&v](iterator it) { return std::inserter(v, it); }, 23); for(auto x : v) std::cout << x << std::endl; return 0; } 

L’exemple ne fonctionne que pour les conteneurs qui n’invalident pas leurs iterators lors de l’insertion. Devrais-je simplement me débarrasser des iterators et accepter un conteneur comme argument ou suis-je en insert_iterator manquer quelque chose à propos de insert_iterator qui rend ce type d’utilisation possible?

L’exemple ne fonctionne que pour les conteneurs qui n’invalident pas leurs iterators lors de l’insertion.

Exactement.

Dois-je simplement me débarrasser des iterators et accepter un conteneur comme argument?

Ce serait une possibilité. Une autre solution consisterait à ne pas rendre l’algorithme sur place (c’est-à-dire une sortie vers un autre conteneur / iterator-sortie).

me manque quelque chose à propos de insert_iterator qui rend ce type d’utilisation possible?

insert_iterator est destiné aux insertions répétées à un seul endroit d’un conteneur, par exemple. par un algorithme de transformation.

Les problèmes de votre implémentation n’ont absolument rien à voir avec les propriétés de insert_iterator . Il est garanti que tous les types d’iterators d’insertion dans la bibliothèque standard C ++ restnt valides, même si vous effectuez une insertion dans un conteneur qui invalide potentiellement les iterators lors de l’insertion. Ceci n’est, bien sûr, vrai que si toutes les insertions sont effectuées par l’intermédiaire de l’iterator d’insert.

En d’autres termes, la mise en œuvre des iterators d’insertion garantit que l’iterator se “guérira” automatiquement, même si l’insertion conduit à un événement susceptible d’invalider l’iterator dans le conteneur.

Le problème avec votre code est que les iterators de begin et de end peuvent potentiellement être invalidés par insertion dans certains types de conteneur. C’est le begin et la end qui doivent vous préoccuper dans votre code, pas l’iterator d’insert.

En attendant, vous le faites complètement à l’envers pour une raison quelconque. Vous semblez vous préoccuper d’actualiser l’iterator d’insertion (ce qui est totalement inutile), tout en ignorant complètement les termes begin et end .