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

Langage C++ Discussion :

Convertir un std::vector de std::unique_ptr en un std::vector de pointeurs nus.


Sujet :

Langage C++

  1. #1
    Invité
    Invité(e)
    Par défaut Convertir un std::vector de std::unique_ptr en un std::vector de pointeurs nus.
    Salut!

    Je voudrais n'utiliser les pointeurs intelligent que en interne à ma bibliothèque, le problème c'est que j'ai des std::vector de std::unique_ptr, et je dois alors, les convertir en std::vector de pointeurs nu avant de les renvoyer à l'utilisateur comme ceci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    std::vector<Entity*> getEntities() {       
           std::vector<Entity*> entities;
           for (unsigned int i = 0; i < m_entities.size(); i++) {
                 entities.push_back(m_entities[i].get());
           }
           return entities;
    }

    Ce que je trouve assez lourd, n'y a t'il pas moyen de faire ceci directement ?

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    entities = m_entities;

    Sinon, je pense que je vais coder ma propre classe pour faire cela, d'ailleurs, j'ai déjà commencé à en code une car, au niveau syntaxe ça devient, assez, lourd...

    Pour les pointeurs simple ça va encore mais pour les tableaux de pointeurs ça devient vraiment, overkill. :/

  2. #2
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    non

    mais une simple fonction template à réutiliser partout ferait l'affaire plutôt que
    je vais coder ma propre classe pour faire cela
    m'enfin, comme tu aimes bien réinventer des roues ovales, ne t'en prive pas !
    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 éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Au fond ce que tu souhaites (si j'ai bien compris), c'est permettre à l'utilisateur de parcourir (sans pouvoir la modifier) une collection de Entity. Avec ta solution actuelle, tu imposes trop de choses à l'utilisateur : travailler avec std::vector, et sur des Entity*. Si tes entités étaient stockées comme valeurs dans un std::vector<Entity>, la solution serait simple : il suffit de déclarer un paire de fonctions begin() et end() dans ta classe qui retournent simplement le résultat de m_entities.begin() et m_entities.end(), respectivement. De fait, l'utilisateur manipule directement des Entity&, et sans avoir à se soucier du type exact de la collection (std::vector ou autre).

    Mais comme tu as un std::vector<std::unique_ptr<Entity>>, le problème est un peu plus compliqué, car tu ne dois pas exposer à l'utilisateurs les std::unique_ptr. La solution est de passer par des itérateurs personnalisés qui vont "cacher" ce détail. Le code est assez pénible à écrire car il faut grosso modo refaire à la main le code d'un itérateur standard en ne changeant que l'opérateur de dé-référencement. Je te mets ci-dessous le code générique que j'utilise (C++11, source: github). Il a l'avantage de fonctionner avec n'importe quel conteneur, et n'importe quel type de pointeur (pointeur nu, std::unique_ptr, ...).

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
     
    // Factorisation du code commun dans une classe de base.
    // Que ce soit un iterator, const_iterator, reverse_iterator, ...
    // on a toujours le même comportement, donc inutile de se
    // répéter.
    template<typename ChildIter, typename BaseIter>
    struct ptr_iterator_base_impl {
        BaseIter i;
     
        ptr_iterator_base_impl(const BaseIter& j) : i(j) {}
     
        ChildIter operator ++ (int) {
            ChildIter iter = static_cast<ChildIter&>(*this);
            ++i; return iter;
        }
     
        ChildIter& operator ++ () {
            ++i; return static_cast<ChildIter&>(*this);
        }
     
        ChildIter operator -- (int) {
            ChildIter iter = static_cast<ChildIter&>(*this);
            --i; return iter;
        }
     
        ChildIter& operator -- () {
            --i; return static_cast<ChildIter&>(*this);
        }
     
        template<typename U>
        ChildIter operator + (U d) const {
            return i + d;
        }
     
        auto operator - (const ChildIter& iter) const -> decltype(i - i) {
            return i - iter.i;
        }
     
        template<typename U, typename enable = typename std::enable_if<std::is_arithmetic<U>::value>::type>
        ChildIter operator - (U d) const {
            return i - d;
        }
     
        template<typename U, typename enable = typename std::enable_if<std::is_arithmetic<U>::value>::type>
        ChildIter& operator += (U d) {
            i += d; return static_cast<ChildIter&>(*this);
        }
     
        template<typename U, typename enable = typename std::enable_if<std::is_arithmetic<U>::value>::type>
        ChildIter& operator -= (U d) {
            i -= d; return static_cast<ChildIter&>(*this);
        }
     
        bool operator == (const ChildIter& iter) const {
            return i == iter.i;
        }
     
        bool operator != (const ChildIter& iter) const {
            return i != iter.i;
        }
     
        bool operator < (const ChildIter& iter) const {
            return i < iter.i;
        }
     
        bool operator <= (const ChildIter& iter) const {
            return i <= iter.i;
        }
     
        bool operator > (const ChildIter& iter) const {
            return i > iter.i;
        }
     
        bool operator >= (const ChildIter& iter) const {
            return i >= iter.i;
        }
     
        auto operator * () const -> decltype(**i) {
            return **i;
        }
     
        auto operator -> () const -> decltype(*i) {
            return *i;
        }
     
        BaseIter stdbase() const {
            return i;
        }
    };
     
    template<typename BaseIter>
    class ptr_iterator_base;
     
    // Le const_iterator
    template<typename BaseIter>
    class const_ptr_iterator_base :
        private ptr_iterator_base_impl<const_ptr_iterator_base<BaseIter>, BaseIter> {
     
        using impl = ptr_iterator_base_impl<const_ptr_iterator_base, BaseIter>;
        friend impl;
     
    public :
        const_ptr_iterator_base() = default;
        const_ptr_iterator_base(const BaseIter& j) : impl(j) {}
        const_ptr_iterator_base(const ptr_iterator_base<BaseIter>& iter) : impl(iter.i) {}
        const_ptr_iterator_base(const const_ptr_iterator_base&) = default;
        const_ptr_iterator_base(const_ptr_iterator_base&&) = default;
        const_ptr_iterator_base& operator = (const const_ptr_iterator_base&) = default;
        const_ptr_iterator_base& operator = (const_ptr_iterator_base&&) = default;
     
        using impl::operator*;
        using impl::operator->;
        using impl::operator+;
        using impl::operator-;
        using impl::operator++;
        using impl::operator--;
        using impl::operator+=;
        using impl::operator-=;
        using impl::operator==;
        using impl::operator!=;
        using impl::operator<;
        using impl::operator<=;
        using impl::operator>;
        using impl::operator>=;
        using impl::stdbase;
    };
     
    // L'iterator de base
    template<typename BaseIter>
    class ptr_iterator_base :
        private ptr_iterator_base_impl<ptr_iterator_base<BaseIter>, BaseIter> {
     
        template<typename N>
        friend class const_ptr_iterator_base;
        using impl = ptr_iterator_base_impl<ptr_iterator_base, BaseIter>;
        friend impl;
     
    public :
        ptr_iterator_base() = default;
        ptr_iterator_base(const BaseIter& j) : impl(j) {}
        ptr_iterator_base(const ptr_iterator_base&) = default;
        ptr_iterator_base(ptr_iterator_base&&) = default;
        ptr_iterator_base& operator = (const ptr_iterator_base&) = default;
        ptr_iterator_base& operator = (ptr_iterator_base&&) = default;
     
        using impl::operator*;
        using impl::operator->;
        using impl::operator+;
        using impl::operator-;
        using impl::operator++;
        using impl::operator--;
        using impl::operator+=;
        using impl::operator-=;
        using impl::operator==;
        using impl::operator!=;
        using impl::operator<;
        using impl::operator<=;
        using impl::operator>;
        using impl::operator>=;
        using impl::stdbase;
    };
     
    // NB: tu peux facilement rajouter les reverse_iterator et const_reverse_iterator si besoin
    // Cf. le code sur github.
    Pour rendre les choses plus propres et éviter de polluer ta classe, tu peux utiliser un wrapper qui n'expose que le strict minimum :
    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
    29
    30
    31
    32
    33
    template<typename ValueType>
    struct vector_unique_ptr_wrapper {
    private :
        using base = std::vector<std::unique_ptr<ValueType>>;
        using base_iterator = typename base::iterator;
        using base_const_iterator = typename base::const_iterator;
     
        base& m_vector;
     
    public :
        using iterator = ptr_iterator_base<base_iterator>;
        using const_iterator = const_ptr_iterator_base<base_const_iterator>;
     
        explicit vector_unique_ptr_wrapper(base& vec) : m_vector(vec) {}
     
        iterator begin() {
            return m_vector.begin();
        }
     
        const_iterator begin() const {
            return m_vector.begin();
        }
     
        iterator end() {
            return m_vector.end();
        }
     
        const_iterator end() const {
            return m_vector.end();
        }
     
        // Tu peux, si tu veux, rajouter m_vector.size() aussi
    };
    Avec ce wrapper, le code dans ta classe est simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyClass {
        // Le conteneur que tu manipules en interne
        std::vector<std::unique_ptr<Entity>> m_entities;
     
        // Le reste de ton code
     
    public :
        MyClass() : entities(m_entities) { /* ... */ }
     
        // Tu n'exposes que le wrapper à l'utilisateur
        vector_unique_ptr_wrapper<Entity> entities;
     
        // Le reste de ton code
    };
    Et ça s'utilise comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for (/* const */ Entity& e : obj.entities) {
        // traitement sur 'e' ...
    }
    Du point de vue de l'utilisateur, on peut difficilement faire plus simple.

  4. #4
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Sinon il y a boost qui propose déjà ça (boost.iterator et boost.range).

  5. #5
    Invité
    Invité(e)
    Par défaut
    Ok c'est ce que je cherchais mais une question, ça fonctionne aussi si ma classe Entity est polymorphique ? (Au fait c'est pour ça que j'utilise un pointeur, sinon j'aurai un effet de slicing)

    J'avais pensé faire une classe qui hérite de std::vector<std::unique_ptr<T>> et une fonction de conversion mais, je sais pas si c'est la meilleure solution en plus cela ne fonctionnerait qu'avec un seul type de conteneur.

  6. #6
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Pourquoi renvoyer à l'utilisateur un vecteur de pointeur nus ? Même si on est pas toujours d'accord pour utiliser, ou pas, des pointeurs nus à l'intérieur d'une classe ou d'un fonction ; on est généralement assez d'accord pour dire : « pas de pointeurs nus dans l'interface publique ».
    Donc pour moi tu devrais probablement renvoyer une référence sur le vecteur d'unique_ptr. Si tu veux un truc qui se rapproche plus d'un simple vecteur, tu peux utiliser boost::ptr_vector.

  7. #7
    Invité
    Invité(e)
    Par défaut
    Ha voilà j'ai trouvé un truc pour simplifier la syntaxe.

    Code cpp : 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
     
    template <typename R>
    class SmartPointer {
        public :
        SmartPointer() :
        rm (ResourceManager<R>::Instance()),
        localisation("0") {
            counter = new unsigned int(0);
            (*counter)++;
        }
        SmartPointer(R* resource) :
        rm (ResourceManager<R>::Instance()),
        localisation(rm.make_resource(resource, ResourceManagerBase::INTERNAL)) {
            counter = new unsigned int(0);
            (*counter)++;
        }
        SmartPointer(const SmartPointer& sp) :
        rm (ResourceManager<R>::Instance()),
        localisation(sp.localisation){
            counter = sp.counter;
            (*counter)++;
        }
        template <typename D>
        SmartPointer(const SmartPointer<D>& sp) :
        rm (ResourceManager<R>::Instance()),
        localisation(rm.make_resource(sp.Instance(), ResourceManagerBase::INTERNAL)) {
            (*sp.counter)++;
            counter = new unsigned int(0);
            (*counter)++;
        }
        SmartPointer& operator=(const SmartPointer& sp) {
            (*sp.counter)++;
            (*counter)--;
            R* ptr = const_cast<R*>(sp.rm.getResourceByPath(sp.localisation));
            localisation = rm.make_resource(ptr, ResourceManagerBase::INTERNAL);
            counter = sp.counter;
            return *this;
        }
        template <typename D>
        SmartPointer& operator=(const SmartPointer<D>& sp) {
            (*sp.counter)++;
            (*counter)++;
            D* ptr = const_cast<D*>(sp.getResourceManager().getResourceByPath(sp.getLocalisation()));
            localisation = rm.make_resource(ptr, ResourceManagerBase::INTERNAL);
            counter = sp.counter;
            return *this;
        }
        std::string getLocalisation() const {
            return localisation;
        }
        ResourceManager<R>& getResourceManager() const {
            return rm;
        }
        unsigned int getCounter() {
            return *counter;
        }
        R* operator-> () {
            std::lock_guard<std::recursive_mutex> locker(rec_mutex);
            return const_cast<R*>(rm.getResourceByPath(localisation));
        }
        R* get() const {
            std::lock_guard<std::recursive_mutex> locker(rec_mutex);
            return const_cast<R*>(rm.getResourceByPath(localisation));
        }
        ~SmartPointer() {
            std::lock_guard<std::recursive_mutex> locker(rec_mutex);
            if ((*counter) - 1 < 0)
                (*counter)++;
            (*counter)--;
            if (*counter == 0 && localisation != "0") {
                rm.deleteResourceByPath(localisation, ResourceManagerBase::TYPE::INTERNAL);
            }
        }
        unsigned int* counter;
        private :
        ResourceManager<R>& rm;
        std::string localisation;
     
    };
    template <typename T, typename... A>
    SmartPointer<T> make_smart(A&&... args) {
        std::lock_guard<std::recursive_mutex> locker(rec_mutex);
        SmartPointer<T> sp(new T(std::forward<A>(args)...));
        return sp;
    }
    template <typename... A>
    class SmartContainerPointer {
     
    };
    template <template <typename...> class C, class... A>
    class SmartContainerPointer<C<A...>> : public C<A...> {
     
    };
    template <template <typename, typename> class C, class H, class T>
    class SmartContainerPointer<C<SmartPointer<H>, T>> : public C<SmartPointer<H>, T> {
     
    };
    template <template <typename, typename> class C, class H, class T>
    class SmartContainerPointer<C<H, T>> : public C<H, T> {
    };
    template <template <class> class C, class H>
    class SmartContainerPointer<C<SmartPointer<H>>> : public C<SmartPointer<H>> {
     
    };
    template <template <class> class C, class H>
    class SmartContainerPointer<C<H>> : public C<H> {
     
    };
    template <class H>
    using SmartVectorPointer = SmartContainerPointer<std::vector<SmartPointer<H>>>;
    }

    Utilisation :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    odfaeg::SmartVectorPointer<int> v;
    v.push_back(odfaeg::make_smart<int>(5));

    Il ne me reste plus qu'à faire un using pour les std::map et les autres types de contenaires!

  8. #8
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    ça fonctionne aussi si ma classe Entity est polymorphique ?
    Oui, tes objets sont toujours stockés sous forme de std::unique_ptr<Entity>, donc pas de slicing.

    Citation Envoyé par Lolilolight Voir le message
    J'avais pensé faire une classe qui hérite de std::vector<std::unique_ptr<T>> et une fonction de conversion mais, je sais pas si c'est la meilleure solution en plus cela ne fonctionnerait qu'avec un seul type de conteneur.
    La conversion va être coûteuse, j'éviterais cette approche. Tu peux envisager d'hériter de std::vector<std::unique_ptr<T>>, mais uniquement par héritage privé. Il est probable que tu arrives à quelque chose qui soit proche de boost::ptr_vector (merci Flob pour le lien vers boost, je ne l'utilise pas et du coup je l'oublie toujours) ou plutôt du ptr_vector que j'utilise (source: github). Ma version est taillée pour l'utilisation avec std::unique_ptr et ne permet pas de stocker de pointeur invalide (nullptr ou pointeur vers de la mémoire non allouée) car les pointeurs ne sont jamais exposés à l'interface publique : la construction se fait "inplace" par copie ou mouvement et les éléments sont retournés directement par référence. En utilisant cette classe, tu peux avoir un comportement identique au code que j'ai cité ci-dessus en écrivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyClass {
        // Le conteneur que tu manipules en interne
        ptr_vector<Entity> m_entities;
     
        // Le reste de ton code
     
    public :
        MyClass() : entities(m_entities) { /* ... */ }
     
        // Tu n'exposes qu'une référence constante à l'utilisateur
        const ptr_vector<Entity>& entities;
     
        // Le reste de ton code
    };

  9. #9
    Invité
    Invité(e)
    Par défaut
    Ok je vais essayer quelque chose de similaire à boost::ptr_vector.

    Je ne fais aucune conversion ici, j'utilise juste un using pour facilité la syntaxe, ma classe odaeg::SmartPointer est similaire à std::shared_pointer mais avec moins de code que celle de la STL qui semble assez lourde. (D'ailleurs la plupart des classes de la STL sont assez lourde au niveau du volume de code et aucun using pour simplifier l'écriture, même si c'est parfois mieux de réutiliser certaines classe de la STL plutôt que de les réinventer, pour les classes vraiment simple je préfère la refaire)

    Code cpp : 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
     
    template <typename R>
    class SmartPointer {
        public :
        SmartPointer() :
        rm (ResourceManager<R>::Instance()),
        localisation("0") {
            counter = new unsigned int(0);
            (*counter)++;
        }
        SmartPointer(R* resource) :
        rm (ResourceManager<R>::Instance()),
        localisation(rm.make_resource(resource, ResourceManagerBase::INTERNAL)) {
            counter = new unsigned int(0);
            (*counter)++;
        }
        SmartPointer(const SmartPointer& sp) :
        rm (ResourceManager<R>::Instance()),
        localisation(rm.make_resource(sp.get(), ResourceManagerBase::INTERNAL)){
            counter = sp.counter;
            (*counter)++;
        }
        template <typename D>
        SmartPointer(const SmartPointer<D>& sp) :
        rm (ResourceManager<R>::Instance()),
        localisation(rm.make_resource(sp.get(), ResourceManagerBase::INTERNAL)) {
            counter = sp.counter;
            (*counter)++;
        }
        SmartPointer& operator=(const SmartPointer& sp) {
            localisation = rm.make_resource(sp.get(), ResourceManagerBase::INTERNAL);
            (*sp.counter)++;
            (*counter)--;
            counter = sp.counter;
            return *this;
        }
        template <typename D>
        SmartPointer& operator=(const SmartPointer<D>& sp) {
            localisation = rm.make_resource(sp.get(), ResourceManagerBase::INTERNAL);
            (*sp.counter)++;
            (*counter)--;
            counter = sp.counter;
            return *this;
        }
        std::string getLocalisation() const {
            return localisation;
        }
        ResourceManager<R>& getResourceManager() const {
            return rm;
        }
        unsigned int getCounter() {
            return *counter;
        }
        R* operator-> () {
            std::lock_guard<std::recursive_mutex> locker(rec_mutex);
            return const_cast<R*>(rm.getResourceByPath(localisation));
        }
        R* get() const {
            std::lock_guard<std::recursive_mutex> locker(rec_mutex);
            return const_cast<R*>(rm.getResourceByPath(localisation));
        }
        bool operator< (const SmartPointer& sp) const {
            return get() < sp.get();
        }
        ~SmartPointer() {
            std::lock_guard<std::recursive_mutex> locker(rec_mutex);
            (*counter)--;
            if (*counter == 0 && localisation != "0") {
                rm.deleteResourceByPath(localisation, ResourceManagerBase::TYPE::INTERNAL);
            }
        }
        unsigned int* counter;
        private :
        ResourceManager<R>& rm;
        std::string localisation;
     
    };
    template <typename T, typename... A>
    SmartPointer<T> make_smart(A&&... args) {
        std::lock_guard<std::recursive_mutex> locker(rec_mutex);
        SmartPointer<T> sp(new T(std::forward<A>(args)...));
        return sp;
    }
    template <typename... A>
    class SmartContainerPointer {
     
    };
    template <template <typename...> class C, class... A>
    class SmartContainerPointer<C<A...>> : public C<A...> {
     
    };
    template <template <typename, typename> class C, class H, class T>
    class SmartContainerPointer<C<SmartPointer<H>, T>> : public C<SmartPointer<H>, T> {
     
    };
    template <template <typename, typename> class C, class H, class T>
    class SmartContainerPointer<C<H, T>> : public C<H, T> {
    };
    template <template <class> class C, class H>
    class SmartContainerPointer<C<SmartPointer<H>>> : public C<SmartPointer<H>> {
     
    };
    template <template <class> class C, class H>
    class SmartContainerPointer<C<H>> : public C<H> {
     
    };
    template <class H>
    using SmartVectorPointer = SmartContainerPointer<std::vector<SmartPointer<H>>>;
    template <class H, class T>
    using SmartMapPointerK = SmartContainerPointer<std::map<SmartPointer<H>, T>>;
    template <class H, class T>
    using SmartMapPointerV = SmartContainerPointer<std::map<H, SmartPointer<T>>>;
    template <class H, class T>
    using SmartMapPointer = SmartContainerPointer<std::map<SmartPointer<H>, SmartPointer<T>>>;
    }

    De plus l'utilisation de std::unique_ptr et std::shared_ptr compliquent assez bien des choses.
    Un std::unique_ptr n'est rien d'autre qu'un std::shared_ptr mais qui n'est pas copier, mais lorsqu'on a besoin de copier le pointeur ou bien de récupérer des pointeurs nus pour les utiliser temporairement (surtout dans un contenaire, ça devient assez galère et assez lourd au niveau de la conversion je trouve.) :/

    Autant faire une seule classe moins lourde pour tout, plutôt que de faire des conversions de std::vector<std::unique_ptr<T>> en std::vector<std::shared_ptr<T>> (ou bien en pointeurs nu) qui serait je pense, trop coûteuses.
    Dernière modification par Invité ; 28/09/2014 à 13h42.

  10. #10
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Ok je vais essayer quelque chose de similaire à boost::ptr_vector.
    Et utiliser déjà ce qui existe, c'est pas envisageable ? Surtout quand l'existant est header only.

    Citation Envoyé par Lolilolight Voir le message
    Je ne fais aucune conversion ici, j'utilise juste un using pour facilité la syntaxe, ma classe odaeg::SmartPointer est similaire à std::shared_pointer mais avec moins de code que celle de la STL qui semble assez lourde. (D'ailleurs la plupart des classes de la STL sont assez lourde au niveau du volume de code et aucun using pour simplifier l'écriture, même si c'est parfois mieux de réutiliser certaines classe de la STL plutôt que de les réinventer, pour les classes vraiment simple je préfère la refaire)
    Je vois pas trop l'intérêt de voir la quantité de code que représente l'implémentation (par ton compilation) des classes de la bibliothèque standard ? C'est l'interface et les performances de l'implémentation qui comptent, pas la quantité de code. Et sur ces deux points, je suis prêt à parier que l'équipe derrière ton compilateur fait mieux que toi.

    Citation Envoyé par Lolilolight Voir le message
    De plus l'utilisation de std::unique_ptr et std::shared_ptr compliquent assez bien des choses.
    Non, ils simplifient les choses. Mais comme tu ne dis jamais ce que tu fais réellement, il est difficile de te montrer comment bien les utiliser.

    Citation Envoyé par Lolilolight Voir le message
    Un std::unique_ptr n'est rien d'autre qu'un std::shared_ptr mais qui n'est pas copier, mais lorsqu'on a besoin de copier le pointeur ou bien de récupérer des pointeurs nus pour les utiliser temporairement (surtout dans un contenaire, ça devient assez galère et assez lourd au niveau de la conversion je trouve.) :/
    N'importe quoi, unique_ptr n'est pas rien d'autre qu'un shared_ptr. Et tes galères sont surment du à un problème de conception. Il y a peu de bonne raison de récupérer un conteneur pour le faire sortir de l'interface de la classe, mets plutôt ce qu'il faut dans l'interface de ta classe pour ne pas avoir à faire ça. Mais à nouveau comme tu nous présentes des questions techniques et pas les problématiques de fond, difficile de te donner les bonnes solutions. (Et même pour ce besoin, boost et le concept de range répond très bien à la problématique)

    Citation Envoyé par Lolilolight Voir le message
    Autant faire une seule classe moins lourde pour tout, plutôt que de faire des conversions de std::vector<std::unique_ptr<T>> en std::vector<std::shared_ptr<T>> (ou bien en pointeurs nu) qui serait je pense, trop coûteuses.
    Non, aucun raison de faire ça. A part risquer d'introduire plus de bugs (car plus de code), ça n'apporte rien (encore moins quand c'est des éléments de la bibliothèque standard).

  11. #11
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Mais comme tu as un std::vector<std::unique_ptr<Entity>>, le problème est un peu plus compliqué, car tu ne dois pas exposer à l'utilisateurs les std::unique_ptr. La solution est de passer par des itérateurs personnalisés qui vont "cacher" ce détail.
    Je trouve désormais les itérateurs assez peu agréables à manipuler. Je crois que dans ce genre de situation, je préfèrerais :
    - Soit retourner un array_view (semblable au string_view en cours de standardisation, et en plus comme ça n'existe pas par défaut, ça laisse à Lolilolight la possibilité de s'adonner à son penchant pervers de ne pas réutiliser l'existant ). Voir par exemple http://llvm.org/docs/doxygen/html/cl...1ArrayRef.html. Quelquechose qui corresponde en tout cas à un range tel que défini par la range-based for loop.
    - Soit si tout ce que je veux permettre est le parcours, fournir une fonction de parcours qui prenne en paramètre une lambda :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class MyClassWithVectorOfSmartPointers
    {
        template<class F>
        void forEachElements(F f)
        {
            for(auto p : myData)
                f(p.get())
        }
    }
     
    myClassWithVectorOfSmartPointers.forEachElements([](Element &e) {
        // Do something with e
        });
    C'est moins flexible, mais bien plus simple à mettre en place...
    Citation Envoyé par Ehonn Voir le message
    Pourquoi renvoyer à l'utilisateur un vecteur de pointeur nus ? Même si on est pas toujours d'accord pour utiliser, ou pas, des pointeurs nus à l'intérieur d'une classe ou d'un fonction ; on est généralement assez d'accord pour dire : « pas de pointeurs nus dans l'interface publique ».
    Je ne sais pas trop. Je suis d'accord pour ne pas manipuler de pointeurs nus possédant la donnée (dans une interface publique ou en interne). Et j'aimerais bien aussi un observer_ptr standardisé. Mais en l'absence de ce dernier, je trouve que des pointeurs nus observant ont encore leur place dans une interface (les références ou les optional<T&> ne sont pas adaptées partout).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  12. #12
    Membre éclairé

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Points : 877
    Points
    877
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Ca ne répond pas vraiment à la question initiale, mais avoir une fonction update pour chaques entities éviterait sans doûte de devoir y acceder ?! (Si c'est bien l'ébauche d'un component/entity system)

  13. #13
    Invité
    Invité(e)
    Par défaut
    En théorie non je n'ai pas besoin d'y accéder mais, je préfère quand même utiliser quelque chose qui simplifie la syntaxe lors de la déclaration de mon vecteur de pointeurs.

    Pour pas me taper l'écriture du std::vector<std::unique_ptr<Entity>> à chaque coup.

    Déjà le std::make_unique<Entity> est plus lourd que le new à écrire, quand t'a qu'une entité à ajouté de le vector ça va mais quand t'en a plusieurs ça devient un petit peu plus lourds, j'aurai plutôt tendance à préférer un new, enfin soit..., chacun sont point de vue. ^^

    PS : De plus, je ne pense pas que le for each et les optionnals<E&> soit adapté à tout les cas d’utilisations comme le dis JolyLoïc.

  14. #14
    Membre éclairé

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Points : 877
    Points
    877
    Billets dans le blog
    1
    Par défaut
    Comment ça à chaque coup ? Il est à définir à un endroit non ?

    De plus si c'est juste la longueur de la déclaration qui pose problème, un simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    using EntityVector = std::vector<std::unique_ptr<Entity>>;
    devrait suffire ?

    Et je vais peut être (encore) dire une bétise mais il est possible de faire un new dans le constructeur de l'unique_ptr
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::vector<std::unique_ptr<Entity>> vec;
    vec.emplace_back(new Entity(...));

  15. #15
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Pour le deuxième, faire une fonction make_entity (?)

  16. #16
    Invité
    Invité(e)
    Par défaut
    Non il est défini à plusieurs endroit, un qui contient toutes les entités du monde, et un autre qui ne contient que les entités visible que je dois d'ailleurs passer aux composants de rendu de la scene.

    J'ai besoin de faire une boucle qui parcours toutes les entités du monde, et d'ajouter celles qui sont visible, dans un vecteur temporaire, de plus, je ne mets à jour ce vecteur que quand cela est nécessaire, c'est à dire quand la caméra bouge et pour entité animée je doit aussi remettre le vecteur temporaire à jour en changeant l'entité courante à afficher, de ce faîtes je ne refais pas une mise à jour à chaque complète de la frame à chaque fois qu'une animation est modifiée sinon ça serait trop lourd et je passe ce vecteur temporaire au composant de rendu qui lui applique les shaders, le blending, etc... et rend le tout.

    Je voudrais aussi préciser que l'entity system qui met à jour la scene lorsque la caméra bouge s'exécute dans un thread différent

    Donc il faut de que je passe les std::unique du vecteur aux std::shared_ptr de mon vecteur temporaire, donc, faire un observer mais pour un std::unique_ptr, ce que je n'ai bien sûr pas envie de faire donc j'ai préféré faire ma classe personnalisée pour les pointeurs intelligent et j'utilise un using pour simplifier l'écriture.

    En général j'évite d'utiliser des std::shared_ptr quand cela n'est pas nécessaire et même dans un contexte multi-thread, j'essaye de ne pas les utiliser, le seul moment ou je les utilise c'est quand j'ai par exemple plusieurs thread et que j'ai pas envie bloquer un thread jusqu'à qu'il ai fini d'utiliser la ressource avant de libérer la ressource mais c'est rare que je sois dans ce cas là, en général j'essaie d'utiliser un thread qui tourne en continu jusqu'à la fin du programme avec un boucle et des if dans la fonction exécutée par le thread et une variable de condition au besoin ou bien un join et je stop le thread à la fin du programme.

  17. #17
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par Lolilolight Voir le message
    Non il est défini à plusieurs endroit, un qui contient toutes les entités du monde, et un autre qui ne contient que les entités visible que je dois d'ailleurs passer aux composants de rendu de la scene.

    J'ai besoin de faire une boucle qui parcours toutes les entités du monde, et d'ajouter celles qui sont visible, dans un vecteur temporaire, de plus, je ne mets à jour ce vecteur que quand cela est nécessaire, c'est à dire quand la caméra bouge et pour entité animée je doit aussi remettre le vecteur temporaire à jour en changeant l'entité courante à afficher, de ce faîtes je ne refais pas une mise à jour à chaque complète de la frame à chaque fois qu'une animation est modifiée sinon ça serait trop lourd et je passe ce vecteur temporaire au composant de rendu qui lui applique les shaders, le blending, etc... et rend le tout.
    Heuu... tu crois pas que tu te fais du mal pour rien là

    Tu ne devrais avoir tableau contenant tous les objets du monde, point barre.

    Le tableau qui reprend les éléments devant être affichés devrait se limiter à un tableau d'entiers non signé (size_t ) (*) correspondants aux index des éléments que tu dois afficher dans le tableau qui contient tous les objets du monde.

    En gros, tu as un "gestionnaire" qui représente les tous les objets du monde et qui prend une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class ObjectHolder{
    public:
        /* la fonction qui nous intéresse : récupérer une référence sur l'objet à afficher */
        Entity  const  & fromIndex(size_t index) const{
            assert(index < items_.size());
            assert(items_[index]!=nullptr);
            return *(items_[index].get());
        }
        /* ... d'autres fonctions sans doute utiles viennent ici */
    private:
        std::vector<std::unique_ptr<Entity>> items_;
    };
    Et tu as une classe qui s'occupe de tracer les différents objets dont on donne l'index sous une forme proche de
    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
    class ObjectDrawer{
    public:
        /* ... */
        /* fournie uniquement par facilité ;) */
        void draw(std::vector<size_t> const & idexes) const{
            for(auto it : indexes) {
                draw(it);
            }
        }
        void draw(size_t index) const{
            items_.byIndex(index).draw();
        }
    private:
        ObjectHolder const & items_;
    };
    (oui, je sépare la responsabilité qui consiste à maintenir les différents objets du monde et celle qui consiste à les faire afficher... SRP, quand tu nous tient )
    et le tout serait utilisé sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::vector<size_t> toDraw = whatShouldBeDrawn(/*... */); // (**)
    ObjectDrawer drawer(/* ... */);  // c'est peut être un membre de la classe qui implémente ce code ;)
    drawer.draw(toDraw);
    (*) En fait, je ne suis pas sur du tout qu'un tableau soit la collection la plus efficace... un octree faciliterait sans doute un peu la recherche des éléments devant être affichés
    (**) ll faut bien déterminer, à un moment donné, quels sont les éléments à afficher... on dira que c'est ici que la magie opère
    Je voudrais aussi préciser que l'entity system qui met à jour la scene lorsque la caméra bouge s'exécute dans un thread différent
    Tant que tu n'essaye pas de modifier les indexes existants (et devant être affichés), tu n'as aucun problème.

    En gros, l'ajout (à la fin du tableau) ne posera aucun problème, seules la suppression ou l'insertion (au début ou "au milieu" du tableau) pourraient faire en sorte que les indexes soient décalés... à toi de faire en sorte que ces options ne soient utilisées que quand il est "sécure" de le faire
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  18. #18
    Invité
    Invité(e)
    Par défaut
    Excuse moi j'ai oublier de préciser certaines choses :
    Non, je n'utilise pas d'octree ni de BSP-TREE pour la simple et bonne raison que je connais pas la taille de la map à l'avance, il faudrait à chaque fois reconstruire l'octree ou bien le BSP-TREE à chaque fois que je rajoute un élément sur la map, ce qui serait, assez lourd.

    A la place, j'utilise un système de cases, les cases ont une certaine taille, possèdent une certaine valeur pour le décalage en x, y et z pour la 3D ainsi je peux récupérer toutes les cases qui se trouvent dans la boîte englobante de la caméra en fonction de la perspective utilisée par le jeux. (2D, 2D isométrique ou bien 3D)

    Les cases contiennent toutes les entités présentent dans la zone occupée par la case, je peux ainsi récupérer toutes les entités qui sont dans une zone.

    Donc finalement je n'utilise pas qu'un seul std::vector pour les entités, j'utilise un std::vector par case, donc, je ne peux pas récupérer les indices, je suis obligé de récupérer les entités qui sont visibles à l'intérieur des cases qui sont en intersections avec la boîte englobante de la caméra, ça m'évite de devoir parcourir toutes les entités du monde, et de vérifier si elles sont visible ou non ce qui serait trop lourd.

    Mon algorithme date des décennies à l'époque ou j'ai décidé de commencer à coder un jeux, et est tiré du moteur d'un jeux existant donc..., je ne pense pas que je me suis compliqué la vie par plaisir, loin de là.

    Le seul inconvénient qu'il reste c'est le case ou les entités sont très rapprochée et donc beaucoup d'entités dans la même case, mais je compte optimiser cela plus tard en combinant les avantages d'une structure de type grille et de type tree en rajoutant un BSP-TREE dans chaque case.

    Jusqu'à maintenant c'est la meilleure structure que j'ai pu trouvée, et, c'est d'ailleurs celle qu'ont m'a conseillée.

    Avec un Octree il me faudrait aussi un std::vector par noeud. ^^

    A moins que ce que tu me suggère, est de mettre les indices des entités dans les cases plutôt que de mettre les entités dans les cases, et de faire un vecteur contenant toutes les entités du monde plutôt que d'en faire un par case, alors vu comme ça ça devrait être possible je pense en effet. ^^

    PS : par contre ça serait plus embêtant pour les entités ayant des entités enfants, (les animations squelettiques par exemples), pour des raisons d'optimisation je ne stock que l'animation parent et ensuite je dois tester si l'animation parent est visible, ensuite, je dois tester pour les animations enfants, de l'animation parent, en faisant gaffe à chaque fois de ne pas ajouter deux fois la même entité si elle est présente dans une même case, donc, je devrais reprendre l'indice de l'entité parente et puis récupérer les entités enfants, hum, je ne pense pas que ça sera plus simple finalement, car, je devrais stocker chaque indice dans la classe Entity.
    Dernière modification par Invité ; 29/09/2014 à 17h03.

  19. #19
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Excuse moi j'ai oublier de préciser certaines choses :
    Non, je n'utilise pas d'octree ni de BSP-TREE pour la simple et bonne raison que je connais pas la taille de la map à l'avance, il faudrait à chaque fois reconstruire l'octree ou bien le BSP-TREE à chaque fois que je rajoute un élément sur la map, ce qui serait, assez lourd.
    Humm, soit... je suis bien obligé de te faire confiance parce que je ne connais rien de ton projet ni d ce que tu as fait
    A la place, j'utilise un système de cases, les cases ont une certaine taille, possèdent une certaine valeur pour le décalage en x, y et z pour la 3D ainsi je peux récupérer toutes les cases qui se trouvent dans la boîte englobante de la caméra en fonction de la perspective utilisée par le jeux. (2D, 2D isométrique ou bien 3D)
    Cela peut être cohérent Mais
    Les cases contiennent toutes les entités présentent dans la zone occupée par la case, je peux ainsi récupérer toutes les entités qui sont dans une zone.
    Pourquoi vouloir placer les entités dans tes cases, et non "uniquement" l'index qui te permettrait d'accéder à ces entités... Moins tu en dis dans ton code quant à ce qui est utilisé, mieux tu te porteras
    Donc finalement je n'utilise pas qu'un seul std::vector pour les entités, j'utilise un std::vector par case, donc, je ne peux pas récupérer les indices, je suis obligé de récupérer les entités qui sont visibles à l'intérieur des cases qui sont en intersections avec la boîte englobante de la caméra, ça m'évite de devoir parcourir toutes les entités du monde, et de vérifier si elles sont visible ou non ce qui serait trop lourd.
    Mais la question reste : pourquoi vouloir absolument placer tes entités dans le tableau que tes cases maintiennent utilise des indexes, ce sont des valeur numériques, ce qui est particulièrement léger en mémoire et ca peut être copié, affecté, déplacé et tout ce que tu veux, sans que cela ne pose le moindre problème de sémantique
    Mon algorithme date des décennies à l'époque ou j'ai décidé de commencer à coder un jeux, et est tiré du moteur d'un jeux existant donc..., je ne pense pas que je me suis compliqué la vie par plaisir, loin de là.
    Rien que ca, ca fait peur!!!!

    L'algorithme n'est peut être pas mauvais, bien que je devrais peut être dire : l'algorithme n'était peut être pas mauvais à l'époque ou le moteur de jeu en question avait le vent en poupe.

    Mais les temps évoluent et C++11 nous a apporté un tas de mécanismes qui "officialisent" un mode de pensée différent qui n'était pas répandu ne serait-ce que dans les années 90 (si tant est qu'il existait à l'époque ).

    Ton problème est que les pointeurs intelligents te posent des soucis, mais tu veux pouvoir les utiliser malgré tout pour la sécurité qu'ils peuvent apporter tu dois donc accepter l'idée de modifier quelque peu ta manière de penser afin de t'abstraire de la notion même d'entité partout où il est possible de le faire

    Tu as tout à gagner à revoir très sérieusement les responsabilités de tes différentes classes et à faire en sorte que chaque classe ne s'occupe réellement que d'une seule et unique chose. Ce faisant, tu gagnera en évolutivité et en simplicité dans ton code. Et surtout, tu te rendra compte que l'utilisation d'indexes te facilitera énormément la vie car tu reste parfaitement libre de les transmettre comme tu veux où tu veux
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  20. #20
    Invité
    Invité(e)
    Par défaut
    Oui m'enfin, je ne sais pas car pour que je puisse remettre à jour les entités enfants pour les entités parents, ça va être assez compliqué, car, dans le 1er vecteur je ne stocke que les entités parents pour des questions d'optimisation, au niveau mémoire je ne pense pas que ça changera grand chose, que j'utilise un indice ou bien une adresse sur une entités (un pointeur donc), ça restera un type 64 bits au pire, de plus, je dois récupère les entités visibles enfants des entités visibles parents par récursion.

    Je ne suis pas très convaincu que cela changerait grand chose au niveau sécurité et au niveau performance. (Pour moi les indices et les pointeurs c'est à peu près pareil, ça référence quelquechose dans le but de prendre moins de place en mémoire, les indices me servent juste à changer l'ordre d'affichage des sommets dans le cas d'OPENGL (ou là, il est mieux d'utiliser des indices plutôt que des pointeurs), mais je n'ai pas besoin de changer l'ordre d'affichages des entités, donc finalement je ne pense pas que j'aie vraiment besoin de changer mon code, l'ordre d'affichage je le défini en fonction de la position en z des entités, mais aussi en fonction de la profondeur du pixel et de la transparence avec mon shader pour les primitives ayant des positions en z différentes et ayant des pixels transparents. (Par exemple lorsque deux quads avec des pixels semi-transparent se croisent en profondeur.)

Discussions similaires

  1. std::vector : dynamique ou statique, pile et tas
    Par salseropom dans le forum SL & STL
    Réponses: 7
    Dernier message: 24/01/2005, 13h22
  2. std::sort() sur std::vector()
    Par tut dans le forum SL & STL
    Réponses: 20
    Dernier message: 05/01/2005, 19h15
  3. char[50] et std::vector<>
    Par tut dans le forum SL & STL
    Réponses: 9
    Dernier message: 12/10/2004, 13h26
  4. Réponses: 8
    Dernier message: 26/08/2004, 18h59
  5. Sauvegarde std::vector dans un .ini
    Par mick74 dans le forum MFC
    Réponses: 2
    Dernier message: 12/05/2004, 13h30

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