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 :

Pourquoi std::unique_ptr ne propage-t-il pas const ?


Sujet :

Langage C++

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

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut Pourquoi std::unique_ptr ne propage-t-il pas const ?
    Bonjour,

    Actuellement, dans std::unique_ptr<T, Deleter>, on a des fonctions constantes qui permettent de modifier la donnée pointée de type T :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    pointer get() const;
    pointer operator->() const;
    typename std::add_lvalue_reference<T>::type operator*() const;
    avec pointer qui correspond à std::remove_reference<Deleter>::type::pointer si ce type existe, T* sinon.

    Pourquoi std::unique_ptr a-t-il été conçu ainsi et pas comme ci-dessous ?
    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
    template<class T, class Deleter = std::default_delete<T>>
    class unique_ptr
    {
    private:
        typedef typename std::add_const<T>::type const_T;
        // ...
    public:
        typedef T&       reference;
        typedef const_T& const_reference;
        typedef T*       pointer;
        typedef const_T* const_pointer;
        pointer         get();
        const_pointer   get() const;
        pointer         operator->();
        const_pointer   operator->() const;
        reference       operator*();
        const_reference operator*() const;
        // ...
    };
    Une partie de la réponse est que std::unique_ptr a été conçu pour remplacer entièrement std::auto_ptr, mais la même question s'applique à ce dernier.
    Pourquoi std::auto_ptr<T> contient-il ces fonctions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    T* get()        const;
    T* operator->() const;
    T& operator*()  const;
    au lieu des fonctions ci-dessous ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    T*       get();
    const T* get()        const;
    T*       operator->();
    const T* operator->() const;
    T&       operator*();
    const T& operator*()  const;
    Actuellement, pour propager const, on peut utiliser std::experimental::propagate_const.
    Par exemple, sur la page de en.cppreference.com consacrée à PImpl, le pointeur intelligent utilisé est un std::experimental::propagate_const<std::unique_ptr<impl>>.

    Mais à quoi ça sert de pouvoir ne pas propager const avec un std::unique_ptr ?

    Pour l'instant, le seul cas où ça m'a servi, c'est quand j'ai utilisé un std::unique_ptr<ClasseMalCodee>ClasseMalCodee était une classe d'une bibliothèque externe où il manquait des const.

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Parce qu'ajouter const à un pointeur ne rend pas la valeur constante ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    using P = int *;
    P const p = ...;
    *p = 2; // ok
    C'est discutable, mais l'inverse empêche de remplacer des pointeurs par des pointeurs intelligents dans toutes les situations.

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

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    Quand on a un pointeur qui pointe vers une donnée qu'il ne possède pas, c'est normal que const ne soit pas automatiquement propagé.

    Mais, un std::unique_ptr<T>, en principe, c'est un peu comme un std::optional<T> pour lequel la donnée est stockée ailleurs dans la mémoire dynamique au lieu d'être stockée sur place, avec les autres changements que cela implique.
    Mais je ne vois pas pourquoi std::unique_ptr ne propagerait pas const alors que std::optional le fait bien.

    Ce qui renforce mon étonnement, c'est que d'autres bibliothèques qui ont l'équivalent de std::unique_ptr ne propagent pas const non plus, par exemple boost::scoped_ptr dans Boost et QScopedPointer dans Qt.

    Pour illustrer l'étrangeté de la non propagation de const avec std::unique_ptr, admettons que j'ai un objet sacDeFruits qui contient un std::vector<std::unique_ptr<Fruit>> dont le premier élément contient un pointeur vers un objet de type Pomme et le deuxième un pointeur vers un objet de type Poire.
    Si mon objet sacDeFruits est const, je ne peux changer ni le nombre de fruits, ni leurs types, mais je peux quand même modifier les fruits (par exemple leurs dates de péremption).

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Le problème majeur, c'est qu'on ne peut pas inconditionnellement propager const, parce qu'il y a toujours le potentiel pour du code qui a besoin d'un pointeur intelligent qui ne le propage pas!
    Il faut donc que la propagation du const, s'il y a, reste optionnelle, ce qui complique le template et surtout les copies déplacements entre instances: Faut-il interdire le déplacement depuis un pointeur propageant vers un pointeur non-propageant? etc.

    Edit: J'ai trouvé une raison beaucoup plus simple, liée justement à la possession d'objet par un autre: Un objet peut être fait pour garder toute sa vie un pointeur vers un autre, tout en ayant besoin de le modifier:

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class MonObjet
    {
    	const unique_ptr<Truc> pTruc;
    public:
    	MonObjet(unique_ptr<Truc> && pTruc) : pTruc(move(pTruc)) { if(pTruc==nullptr) throw invalid_argument("pTruc"); }
     
    	void FaireQuelqueChose() { pTruc ->MethodeVirtuelleNonConst(); }
    };
    Ici, on ne veut clairement pas que unique_ptr propage const, et on n'a pas de raison de le mettre non-const (mais s'il propageait const, on aurait une raison).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Edit: J'ai trouvé une raison beaucoup plus simple, liée justement à la possession d'objet par un autre: Un objet peut être fait pour garder toute sa vie un pointeur vers un autre, tout en ayant besoin de le modifier:

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class MonObjet
    {
    	const unique_ptr<Truc> pTruc;
    public:
    	MonObjet(unique_ptr<Truc> && pTruc) : pTruc(move(pTruc)) { if(pTruc==nullptr) throw invalid_argument("pTruc"); }
     
    	void FaireQuelqueChose() { pTruc ->MethodeVirtuelleNonConst(); }
    };
    Pour ce besoin-là, j'aurais créé un nouveau modèle de classe, memory_guard, qui serait un peu comme std::unique_ptr, mais sans les opérations permettant de pointer ailleurs (reset, release, swap, constructeur de mouvement et affectation de mouvement).

    On aurait la même dualité que pour std::lock_guard et std::unique_lock : un modèle de classe RAII pure dont la ressource est acquise à la construction et n'est libérée qu'à la destruction et un autre modèle de classe un peu plus souple.

    Alors, memory_guard et unique_ptr pourraient propager const tous les deux.

    Dans ton exemple, MonObjet aurait un memory_guard.
    On aurait à la fois l'avantage que tu souhaites (pointer toujours vers le même objet Truc) et l'avantage d'avoir une const-correctness plus cohérente : quand un objet est const, les sous-objets qu'il possède sont const aussi.

  6. #6
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    Quand on a un pointeur qui pointe vers une donnée qu'il ne possède pas, c'est normal que const ne soit pas automatiquement propagé.
    Et du coup, quelle différence il y a entre un pointeur qui possède la donnée et un pointeur qui ne la possède pas ? Pourquoi ne pas posséder la valeur empêcherait la propagation du const ?

    Le problème est que le pointeur à 2 niveaux totalement dissocié où mettre const: le pointeur et le pointé. La stratégie choisie est que le pointeur ne s'occupe que de lui même, pas du pointé. Chacun a ses qualificateurs qui ne sont pas propagés de l'un l'autre.

    D'ailleurs, le même problème se pose avec volatile et là, on ne veut clairement pas le propager.

    Avec un pointeur intelligent, on s'attend naturellement au même comportement: ce n'est pas parce que je ne veux pas modifier la valeur du pointeur que je ne veux pas modifier la valeur du pointé. C'est le cas, std::unique_ptr et consort ne font qu'utiliser le pointeur, jamais la valeur directement. Si on wrap un type T alors on n'accède à un type T en toute circonstance. Si on wrap un type T const, alors on accède à un type T const.

    std::propagate_const répond à un autre problème lié aux templates: Ptr<T> n'est pas convertible en Ptr<T const> sans créer un nouvel objet et dupliquer les pointeurs avec des effets de bord non désirables.

    Citation Envoyé par Pyramidev Voir le message
    Mais, un std::unique_ptr<T>, en principe, c'est un peu comme un std::optional<T> pour lequel la donnée est stockée ailleurs dans la mémoire dynamique au lieu d'être stockée sur place, avec les autres changements que cela implique.
    Mais je ne vois pas pourquoi std::unique_ptr ne propagerait pas const alors que std::optional le fait bien.
    Parce que dans "les autres changements que cela implique" il y a "n'est pas un pointeur". Et surtout parce que toute modification de std::optional modifie forcement la valeur.

  7. #7
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    Citation Envoyé par jo_link_noir Voir le message
    Et du coup, quelle différence il y a entre un pointeur qui possède la donnée et un pointeur qui ne la possède pas ? Pourquoi ne pas posséder la valeur empêcherait la propagation du const ?
    Ne pas posséder la valeur n'empêche pas forcément la propagation du const. Mais, à mon avis, posséder la valeur oblige à propager const.
    Si une classe A possède un pointeur vers une classe B sans posséder B, modifier B ne modifiera pas A. Ainsi, il n'est pas nécessaire de propager const.
    Par contre, si une classe A possède une classe B, modifier B modifiera A. Ainsi, il est nécessaire de propager const, peu importe que l'objet contenu soit derrière un pointeur ou non.

    Dans la suite de mon message, je distinguerai :
    • std::unique_ptr<T, Deleter> qui fonctionne tel qu'il est actuellement, donc qui ne propage pas const.
    • unique_memory<T, Deleter> qui propage const. Ainsi, const unique_memory<T, Deleter> est analogue à const std::unique_ptr<const T, Deleter>.
    • memory_guard<T, Deleter> qui est pareil que unique_memory<T, Deleter>, mais sans les opérations permettant de pointer ailleurs (reset, release, swap, constructeur de mouvement et affectation de mouvement). Ainsi, memory_guard<T, Deleter> est analogue à const std::unique_ptr<T, Deleter> et const memory_guard<T, Deleter> est analogue à const std::unique_ptr<const T, Deleter>.


    Quelqu'un aurait-il un exemple concret où il serait plus pertinent qu'une classe possède un objet membre de type std::unique_ptr plutôt qu'un objet membre de type unique_memory ou memory_guard ?

  8. #8
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    Quelqu'un aurait-il un exemple concret où il serait plus pertinent qu'une classe possède un objet membre de type std::unique_ptr plutôt qu'un objet membre de type unique_memory ou memory_guard ?
    Je pense que unique_memory et memory_guard répondent à 99% des besoins. Ce serait en fait l'équivalent de std::propagate_const<std::unique_ptr<T>> et std::propagate_const<const std::unique_ptr<T>>.

    Le seul cas du 1% qui me vient est par l'intermédiaire de conteneur où memory_guard n'est pas applicable (un std::vector<std::unique_ptr<T>> construit en interne d'une classe est accessible à l'extérieur sans autorisation de modifier le vecteur ou les pointeurs, mais sans restriction sur les valeurs pointées, la classe ne s'occupe que de construire une liste cohérente).
    Chose résolue en partie par un intermédiaire qui s'occupe de cacher le unique_ptr (en retournant toujours un pointeur ou une référence) et en appliquant const au besoin. Une espèce de propagate_const pour les conteneurs.

  9. #9
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    Ah ouais, pas bête.
    Ce serait donc un code dans ce genre-là :
    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
    // Code compilé sur http://coliru.stacked-crooked.com/
    // Version de g++ : 6.1.0
    // Commande : g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
     
    #include <memory>
    #include <type_traits>
    #include <vector>
     
    /*!
     * \brief  Conteneur de pointeurs (nus ou intelligents) dont const est propagé jusqu'aux valeurs pointées.
     * \remark Le type Container peut aussi être une référence.
     */
    template<class Container>
    class propagate_const_pointer_container
    {
    private:
        typedef propagate_const_pointer_container<Container>    self_type;
        typedef typename std::remove_reference<Container>::type container_type;
        typedef typename container_type::value_type             value_type;
        typedef typename std::remove_reference<
            decltype(*std::declval<value_type>())>::type        dereference_type;
        typedef typename std::add_const<dereference_type>::type const_dereference_type;
     
        Container m_container;
     
    public:
        constexpr propagate_const_pointer_container(const self_type&) = default;
        constexpr propagate_const_pointer_container(self_type&&)      = default;
     
        self_type& operator=(const self_type&) = delete;
        self_type& operator=(self_type&&)      = delete;
     
        constexpr propagate_const_pointer_container()
            noexcept(std::is_default_constructible<Container>::value)
        {}
     
        constexpr explicit propagate_const_pointer_container(const Container& c)
            noexcept(std::is_nothrow_copy_constructible<Container>::value) :
            m_container(c)
        {}
     
        template<class Container2>
        constexpr explicit propagate_const_pointer_container(Container2&& c)
            noexcept(std::is_nothrow_constructible<Container, Container2&&>::value) :
            m_container(std::forward<Container2>(c))
        {}
     
        dereference_type& operator[](size_t index)
            noexcept(noexcept(*std::declval<Container>()[index]))
        {
            return *m_container[index];
        }
     
        constexpr const_dereference_type& operator[](size_t index) const
            noexcept(noexcept(*std::declval<Container>()[index]))
        {
            return *m_container[index];
        }
     
        void push_back(const value_type& pointer)
        {
            m_container.push_back(pointer);
        }
     
        void push_back(value_type&& pointer)
        {
            m_container.push_back(std::move(pointer));
        }
     
        // Autres fonctions...
    };
     
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wunused-variable"
     
    int main(int argc, char** argv)
    {
        std::vector<std::unique_ptr<int>> vect_unique;
        vect_unique.push_back(std::make_unique<int>(0));
        vect_unique.push_back(std::make_unique<int>(1));
     
        // Objet similaire à const std::vector<std::unique_ptr<int>>,
        // sauf qu'une référence constante vers lui propage const jusqu'à int.
        propagate_const_pointer_container<const std::vector<std::unique_ptr<int>>> test_unique_const(std::move(vect_unique));
        test_unique_const[0] += 10;
    //  test_unique_const.push_back(std::make_unique<int>(2)); // Ne compile pas.
        const auto& const_ref_test_unique_const = test_unique_const;
    //  const_ref_test_unique_const[0] += 10; // Ne compile pas.
     
        // Objet similaire à std::vector<std::unique_ptr<int>>,
        // sauf qu'une référence constante vers lui propage const jusqu'à int.
        propagate_const_pointer_container<std::vector<std::unique_ptr<int>>> test_unique;
        test_unique.push_back(std::make_unique<int>(0));
        test_unique.push_back(std::make_unique<int>(1));
        test_unique[0] += 10;
        test_unique[1] += 10;
        const auto& const_ref_test_unique = test_unique;
    //  const_ref_test_unique[0] += 10; // Ne compile pas.
     
        std::vector<int*> vect_ptr;
        vect_ptr.push_back(&test_unique[0]);
        vect_ptr.push_back(&test_unique[1]);
     
        // Objet similaire à const std::vector<int*>,
        // sauf qu'une référence constante vers lui propage const jusqu'à int.
        propagate_const_pointer_container<const std::vector<int*>> test_ptr_const(vect_ptr); // passage par copie
        test_ptr_const[0] += 100;
        test_ptr_const[1] += 100;
    //  test_ptr_const.push_back(&test_unique[0]); // Ne compile pas.
        const auto& const_ref_test_ptr_const = test_ptr_const;
    //  const_ref_test_ptr_const[0] += 10; // Ne compile pas.
     
        // Objet contenant un const std::vector<int*>&.
        // Une référence constante vers lui propage const jusqu'à int.
        propagate_const_pointer_container<const std::vector<int*>&> test_ptr_ref_const(vect_ptr); // passage par référence constante
        test_ptr_ref_const[0] += 200;
        test_ptr_ref_const[1] += 200;
    //  test_ptr_ref_const.push_back(&test_unique[0]); // Ne compile pas.
        const auto& const_ref_test_ptr_ref_const = test_ptr_ref_const;
    //  const_ref_test_ptr_ref_const[0] += 10; // Ne compile pas.
     
        // Objet contenant un std::vector<int*>&.
        // Une référence constante vers lui propage const jusqu'à int.
        propagate_const_pointer_container<std::vector<int*>&> test_ptr_ref(vect_ptr); // passage par référence non constante
        test_ptr_ref[0] += 1000;
        test_ptr_ref[1] += 1000;
        test_ptr_ref.push_back(&test_unique[0]);
        const auto& const_ref_test_ptr_ref = test_ptr_ref;
    //  const_ref_test_ptr_ref[0] += 10; // Ne compile pas.
     
        return 0;
    }
     
    #pragma GCC diagnostic pop
    EDIT 30/10/2016 vers 12h15 : grosses modifications du code.
    EDIT 31/10/2016 vers 20h56 : ajout de l'exemple le plus important (avec un propagate_const_pointer_container<const std::vector<std::unique_ptr<int>>>) ainsi que des commentaires.

  10. #10
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    N'empêche que, étant donnée la rareté du cas, je pense que la STL aurait dû proposer par défaut l'équivalent de std::experimental::propagate_const<std::unique_ptr<T, Deleter>> et celui de std::experimental::propagate_const<const std::unique_ptr<T, Deleter>>.

    Dommage que boost::scoped_ptr ait imité la non propagation du const de auto_ptr.

  11. #11
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Pas sûr,

    unique_memory et memory_guard répondent à des besoins de variables membres, mais ne sont pas adaptés pour les variables utilisateurs, surtout memory_guard qui est inutilisable en dehors de ce périmètre. Puisque le transfert de ressource n'est pas possible il se limiterait à l'équivalent d'un dynarray.

    Unique_memory est moins contraignant. Bien qu'il ne serait jamais construit en constant pour la même raison que précédemment: le transfert d'ownership inutilisable (et aussi parce que l'instance à une forte probabilité d'être utilisée en tant que valeur non-constante), cela ne gêne pas. Unique_ptr aurait effectivement pu avoir ce comportement par défaut.

    Note: le seul moment ou la propagation du const est utile pour l'utilisateur est s'il fait une fonction qui prend un pointeur intelligent constant en paramètre. Perso, je pense que cette situation ne devrait jamais apparaître et que la fonction devrait prendre une référence, un pointeur nu ou un non_null_ptr.

    (Au passage, la non propagation de const se retrouve également dans les références et les itérateurs (bien que cela soit pertinent pour celui-là).)

Discussions similaires

  1. Réponses: 1
    Dernier message: 18/05/2006, 14h09
  2. [Etudes] Pourquoi l'e-learning ne s'impose pas définitivement?
    Par kisitomomotene dans le forum Etudes
    Réponses: 4
    Dernier message: 12/05/2006, 18h02
  3. Réponses: 11
    Dernier message: 11/05/2006, 09h05
  4. Réponses: 11
    Dernier message: 04/05/2006, 11h50
  5. Réponses: 3
    Dernier message: 10/05/2005, 14h43

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