Autant pour moi...
Le code pour iterator begin() est plutôt du genre de
et, pour end() proche deCode:
1
2
3
4 iterator begin() { return iterator(buf[0]); }
Code:
1
2
3
4 iterator end() { return iterator(buf[lastutil+1]); }
Version imprimable
A mon avis, tu as intérêt à lire les données au premier déréférencement et à les garder dans l'itérateur jusqu'à ce qu'il bouge. Ca évite d'avoir à le relire si tu déréférences plusieurs fois de suite sans le bouger.
En général, cela se traduit par que tu va avoir un itérateur à gauche et un const itérateur à droite.
Non, c'est une erreur de le croire...
Si l'itérateur est constant, c'est la version const qui sera utilisée (à droite généralement, la gauche demandant une référence non constante).
Si l'itérateur n'est pas constant, c'est la version non const qui sera utilisée, que ce soit à droite ou à gauche.
Le seul moyen de différencier ça (mais qui a ses problèmes), c'est de faire retourner un proxy à l'opérateur de référencement, puis si on appelle l'opérateur = sur le proxy, c'est qu'on était à gauche, si on appelle l'opétateur de cast en T, c'est qu'on était à droite.
Maintenant, à mon avis, et n'ayant que survolé les discussion, ne rien avoir en mémoire est une bêtise. Je verrais bien une structure fichier, qui maintient en mémoire une liste de buffers vivants (un buffer est vivant si au moins un itérateur pointe sur un élément de son contenu, et éventuellement un peu après pour optimiser). Une façon de gérer ça est la possibilité d'aliaser les shared_ptrs :
Tu retournes des pointeurs qui pointent sur un élément, mais qui font vivre non pas l'élément lui même, mais le buffer.Citation:
template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); // never throws
Effects: constructs a shared_ptr that shares ownership with r and stores p.
En conclusion, il n'y a pas de moyen simple pour savoir si on est à gauche ou à droite. On peut juste supposer que si on à affaire à une valeur à gauche, il y des chances qu'un operator=() soit juste derrière.
Ou operator+=() ou operator-=() ou...
En fait il faut trouver le moyen de savoir si le buffer a été modifié par un déréférencement ou pas. C'est peut-être ce que tu exprimais JolyLoic dans la 2ème partie de ton intervention avec les shared_ptr() mais je n'ai rien compris... :oops:
Je vais situer mon souhait dans son contexte, car, bien sûr, quand je parlais de terrabytes, c'était une manière ironique de dire qu'il n'était pas voulu ou possible de tout charger en mémoire.
J'utilise assez souvent des std::vector (par exemple) qui, après construction et remplissage, sont figés et consultés en lecture seule. Je souhaitais donc tout simplement ne pas modifier le code qui consulte ces std::vector.
Ainsi, à la fin de la phase de construction et remplissage du std::vector, je fais l'équivalent d'un file.write(&*vector.begin(),vector.size()*size(T)).
Reste donc l'autre partie du code que je ne souhaite pas changer, mais pour laquelle il faut créer un conteneur (avec son itérateur ? :mrgreen:) qui doit pouvoir se comporter de manière transparente pour les algorithmes du type std::find, std::find_if, std::lower_bound, std::upper_bound, std::equal_range, etc, des algorithmes de consultation qui ne modifient pas le conteneur (dont le contenu se trouverait désormais ailleurs qu'en mémoire).
D'un point de vue plus générique, on pourrait voir mon souhait comme un exercice de création de conteneurs se comportant de la même manière que ceux de la STL, à ceci près qu'il n'y a pas à supposer que le contenu est effectivement mémoire.
Il n'y a pas de "projet conceptualisé" derrière, mais un outil permettant de continuer à utiliser la STL en ayant des dizaines et des dizaines de conteneurs "actifs" simultanément sans trop se soucier de savoir si les limites de mémoire de la machine sont atteintes.
Comme je le disais, j'ai du code qui fonctionne depuis quelques jours. Le conteneur "simule" un vector sur fichier, et l'iterator associé fonctionne très bien avec les quelques algos déjà cités. Il y a juste le déréférencement de l'iterator qui se fait par valeur et non par référence. Tant que le contenu du conteneur n'a pas à être modifié, c'est sans problème. Peut-être devrais-je appeler l'iterator const_iterator.
Si t'avais utilisé Iterator Facade comme je l'avais recommandé, tu n'aurais pas eu à te poser toutes ces questions.
Mmm, ce besoin ressemble énormément à la description de SLXXL (la STL version XXL :D)
Il y a peut être quelques bonnes idées à pécher ?
Désolé Loufoque, ta réponse laconique du 27/2 est passé inaperçue derrière celle de 3Darchi.
Ah ben voilà ! Merci Arzar :D
J'ai trouvé un cas concret pour lequel il vaut mieux retourner une référence plutôt qu'une valeur lors du déréférencement d'un iterator: c'est indispensable si on utilise les std::reverse_iterator.
EDIT: non, pas indispensable finalement. Le 3ème paramètre template permet de spécifier à reverse_iterator ce qu'est "une référence".
EDIT2: ah ben ça dépend du compilateur. Sous VC++6 c'est OK mais pas sous VS2005...