IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

surcharger std::vector pour en faire un vecteur circulaire


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    64
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 64
    Par défaut surcharger std::vector pour en faire un vecteur circulaire
    Bonjour,

    J'ai surchargé std::vector afin de créer un vecteur circulaire. L'idée c'est que si mon vecteur fait une taille de 10, Vect.at(12) me renvoie le troisème objet, ou alors Vect.at(-2) me renvoie l'avant dernier objet ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class CircularVector : public std::vector<T_Obj>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template<typename T_Obj>
    T_Obj &CircularVector<T_Obj>::at(const qint32 &adr) {
     
        qint32 p;
        adr >= 0 ? p = adr%size_ : p = size_ - (-adr)%size_;
     
        return vector<T_Obj>::at(p);
    }
    Cette classe m'est super utile

    Par contre je ne sais pas du tout comment surcharger iterator

    Pour pouvoir faire quelque chose du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(std::vector<float>::iterator it = Vector.begin(); it < Vector.end() + 8; ++it) {...}
    Merci d'avance

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par défaut
    - de l'héritage public pour ça est très malvenu
    - quel serait le sens d'itérer jusqu'à "la fin + 8" ? Tu veux passer en revue plusieurs fois les premiers éléments ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    qint32 p;
        adr >= 0 ? p = adr%size_ : p = size_ - (-adr)%size_;
    Cette écriture est bizarre parce que normalement un ternaire ce serait qint32 p = adr >= 0 ? adr%size_ : size_ - (-adr)%size_;
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Bonjour,

    Coder une classe CircularVector :
    • est long si on fait proprement de l'encapsulation,
    • oblige à transformer les std::vector existants en CircularVector pour pouvoir profiter de la fonctionnalité et
    • n'étend que std::vector, pas les autres types de conteneurs.


    Voici une autre solution qui n'a pas les inconvénients ci-dessus. Elle marche à la fois avec std::vector, std::array et std::deque :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template<class ContainerT, class IndexT>
    typename ContainerT::reference getElementByCircularIndex(ContainerT& container, IndexT index) {
    	const auto size      = container.size();
    	const auto realIndex = index >= 0 ? index%size : size - (-index)%size;
    	return container[realIndex];
    }
     
    template<class ContainerT, class IndexT>
    typename ContainerT::const_reference getElementByCircularIndex(const ContainerT& container, IndexT index) {
    	const auto size      = container.size();
    	const auto realIndex = index >= 0 ? index%size : size - (-index)%size;
    	return container[realIndex];
    }
    Voici encore une autre solution, qui supporte encore plus de types de conteneurs, avec un exemple de code qui l'utilise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <array>
    #include <deque>
    #include <iostream>
    #include <iterator>
    #include <list>
    #include <string>
    #include <vector>
     
    auto getElementByCircularIndex = [](auto& container, auto index) {
    	const auto size          = container.size();
    	auto       inputIterator = container.begin();
    	const auto offset        = index >= 0 ? index%size : size - (-index)%size;
    	std::advance(inputIterator, offset);
    	return *inputIterator;
    };
     
    int main()
    {
    	const std::array <std::string, 7> daysArray  = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
    	const std::deque <std::string>    daysDeque  = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
    	const std::list  <std::string>    daysList   = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
    	const std::vector<std::string>    daysVector = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
    	std::cout << getElementByCircularIndex(daysArray,  14)  << " "; // prints "Monday"
    	std::cout << getElementByCircularIndex(daysDeque,  2)   << " "; // prints "Wednesday"
    	std::cout << getElementByCircularIndex(daysList,   74)  << " "; // prints "Friday"
    	std::cout << getElementByCircularIndex(daysVector, -15) << " "; // prints "Sunday"
    	return 0;
    }

  4. #4
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    De plus, il existe déjà, dans Boost, un circular buffer efficace, testé, validé, amélioré.
    http://www.boost.org/doc/libs/releas...ar_buffer.html

    Je te déconseille vivement d'hériter de vector, pour plusieurs raisons, dont l'absence de destructeur virtuel.
    Si tu tiens à le coder toi-même, préfère la composition (contenir un vector comme membre).

  5. #5
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Une solution pour sortir de ton problème, c'est de comprendre que tu as plusieurs visions possibles de ton conteneur:
    • Itération sur l'ensemble des valeurs, de la première à la dernière (le segment [0 .. n-1])
    • Depuis une position donnée, l'ensemble des valeurs (le segment [i .. n-1] puis le segment [0 .. i-1]
    • En boucle infinie.

    La solution la plus simple serait d'avoir un mécanisme de vues itérables. Ces vues contenant a peine plus qu'une référence sur le conteneur, elles sont "gratuites".
    La vue "un cycle" comprenant un point de départ.
    La vue "infinie" dont l'itérateur end est inatteignable depuis un itérateur vers une valeur valide. (par exemple, en interne, un optional<size_type>)

    De là, il suffit de fournir des fonctions utilitaires dans ta classe, qui retournerait une vue.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    cylic_store<int> store {1,2,3,4};
    for(auto i : store.from(3)) cout << i << endl;

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 10
    Dernier message: 11/09/2017, 04h10
  2. besoin d'aide pour "configurer" un std::vector
    Par mazertys17 dans le forum C++
    Réponses: 12
    Dernier message: 27/04/2015, 13h47
  3. Surcharge opérateur std::vector
    Par boutor dans le forum C++
    Réponses: 24
    Dernier message: 31/08/2011, 15h00
  4. Créer un vecteur de texte pour y faire appel
    Par Aphelio dans le forum MATLAB
    Réponses: 4
    Dernier message: 07/05/2011, 21h11
  5. std::vector, taille du vecteur-> quel fonction
    Par toutounesan dans le forum C++
    Réponses: 3
    Dernier message: 11/09/2007, 15h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo