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 :

Différence entre std::unique_ptr et std::shared_ptr.(Quand les utiliser ?)


Sujet :

Langage C++

  1. #21
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    393
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 393
    Points : 685
    Points
    685
    Par défaut
    Citation Envoyé par leternel Voir le message
    Le propriétaire du pointeur sait quand un observateur commence à regarder, et ne dois pas libérer avant.
    Par contre, ça veut aussi dire que l'observateur doit signaler qu'il a fini de regarder.
    Ce qui revient à faire un compteur de référence, donc shared_ptr...

    Pour le delete, comme je l'ai déjà dit, le problème n'est pas que l'observateur fasse un delete (ça ne serait plus un observateur), mais que le propriétaire fasse un delete alors qu'un observateur utilise la ressource (sauf à faire un compteur de référence)

  2. #22
    Invité
    Invité(e)
    Par défaut
    Salut, j'utilise en effet un contexte multi-thread, et il ne faut pas que les ressources soient libérée avant que l'observateur (qui est le composant de rendu de la scene dans mon cas) ai fini de les utiliser.

    Donc si je comprends bien je n'ai pas trop le choix je devrais utiliser un shared_ptr dans ce cas là.

    Bref jusqu'à maintenant, j'ai utilisé un pointeur nu mais que je pense changé en std::unique_ptr dans mon std::vector et lorsque je quitte l'application, j'utilise une variable de condition qui attends que l'observateur aie fini d'afficher la scene, avant que le thread principal (le main) libère les ressources.

    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
     
    #ifndef ODFAEG_ENTITY_SYSTEM_HPP
    #define ODFAEG_ENTITY_SYSTEM_HPP
    #include <condition_variable>
    #include <mutex>
    #include <thread>
    #include "export.hpp"
    /**
    *\namespace odfaeg
    * the namespace of the Opensource Development Framework Adapted for Every Games.
    */
    namespace odfaeg {
    /**
    * \file entitySystem.h
    * \class EntitiesSystem
    * \brief base class of all entities systems of the odfaeg.
    * \author Duroisin.L
    * \version 1.0
    * \date 1/02/2014
    */
    class ODFAEG_CORE_API EntitySystem {
    public :
        /**
        *\fn EntitySystem ()
        *\brief constructor.
        */
        EntitySystem () : needToUpdate(false) {
            running = false;
            g_notified = true;
        }
        /**
        *\fn void launch()
        *\brief launch the thread to update every entities of the entity system.
        */
        void launch () {
            running = true;
            m_thread = std::thread (&EntitySystem::run, this);
     
        }
        /**
        *\fn void update()
        *\brief function called when we need to update the entities, this function block the current thread until it's finished.
        */
        void update () {
            g_notified = false;
            needToUpdate = true;
            g_signal.notify_one();
            std::unique_lock<std::mutex> locker (g_lock_update);
            g_signal.wait(locker, [&](){return g_notified;});
        }
        /**
        *\fn void run()
        *\brief this function block this thread until we need to update the entities by calling the update function.
        * or if we want to stop the thread.
        */
        void run () {
     
            while (running) {
                std::unique_lock<std::mutex> locker(g_lock_update);
                g_signal.wait(locker, [&](){return needToUpdate || !running;});
                onUpdate();
                g_notified = true;
                needToUpdate = false;
                g_signal.notify_one();
            }
        }
        /**
        *\fn bool isRunning()
        *\brief tells is the thread is running.
        *\return true if the thread is running.
        */
        bool isRunning () {
            return running;
        }
        /**
        *\fn void stop()
        *\brief stop this thread.
        */
        void stop () {
            running = false;
            g_signal.notify_one();
        }
        /**
        *\fn void onUpdate()
        *\brief function to refefines to updates the entities.
        */
        virtual void onUpdate() = 0;
    private :
        std::thread m_thread; /**< an internal thread which updates the entities*/
        bool running, needToUpdate, g_notified; /**< tells if the thread is running, if the entities need to be update by the thread, and, if the thread have finished to update the entities.*/
        std::condition_variable g_signal; /**<condition variable used for the primitive synchronisation of the thread.*/
        std::mutex g_lock_update; /**<mutex used in the condition variable to avoid concurrent access to a variable between different threads*/
    };
    }
    #endif // ENTITY_SYSTEM

    Tant que l'observateur n'a pas fini de mettre la scene à jour (pendant ou bien lors de l'arrêt de l'application c'est à dire lorsque je mets running à false), le thread principal est bloqué et ne peux pas libérer les ressources.

    Donc, je crois que dans ce cas là je peux m'en sortir avec un std::unique_ptr, il y a malheureusement un cas ou je n'ai pas le choix et ou je dois utiliser un std::shared_ptr.

    C'est lorsque par exemple, j'ai un bsp tree ou chaque noeud est une action. (mais ça pourrait être autre chose)
    Je suis obligé d'utiliser un pointeur pour les feuilles du bsp tree dans le .h vu que j'ai pas la définition complète de la classe dans la classe elle même, et je veux lier ces actions à plusieurs BSP-TREE.
    De plus les feuilles du BSP-TREE peuvent être nulle si ce n'est pas une action combinée, donc, raison de plus d'utiliser un pointeur. (std::shared_ptr ou std::unique_ptr)

    Si je fais un std::unique_ptr pour les feuilles du BSP-TREE, le problème est que les actions seront invalide si je veux les utiliser dans un autre BSP-TREE car elles seront déplacée dans les feuilles du premier BSP-TREE.

    Et cette classe n'est pas copiable donc je ne peux pas copier mes actions en les passant dans le constructeur du BSP-TREE et en faisant une allocation dynamique dans le constructeur du BSP-TREE. (C'est une classe à sémantique d'entité) donc je suis obligé de faire un déplacement ou un partage de pointeur.

    Et comme le BSP-TREE ne peut pas devenir propriétaire d'une action, je suis obligé d'utiliser un std::shared_ptr!

    Ou bien alors, je dois rendre la classe Action copiable mais je pense pas que ça soit une bonne idée.

    C'est le seul cas ou je suis obligé d'utilisé un std::shared_ptr dans mon code, dans tout les autres cas je peux utilisé un std::unique_ptr et je pourrais, je pense, très bien me passer du std::shared_ptr.

  3. #23
    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
    Je n'ai pas tous compris à mon message, mais un truc me choque un peu : j'ai l'impression que tu as pensé l'implémentation interne de ton arbre en prenant en compte l'ensemble du problème. Alors que la base de la conception c'est justement de découper la problématique avant de concevoir. Je ne vois pas pourquoi le fait qu'il y est au final plusieurs arbre se partageant des objets influent l'implémentation de l'arbre. Je fais mon arbre sans tenir compte de ce point, ensuite à l'utilisation je passe par une capsule si j'ai besoin d'ajouter une notion de partage.

  4. #24
    Invité
    Invité(e)
    Par défaut
    Bon bah j'ai redéfini le constructeur de copie et l'opérateur d'affectation. (Avec std::shared_ptr je ne devais pas car la classe std::shared_ptr est copiable, tandit que std::unique_ptr ne l'est pas vu que dans la logique on utilise std::unique_ptr pour faire un déplacement et pas une copie.)

    Voila donc ce que j'ai fais :

    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
    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
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
     
    #include "../../../include/odfaeg/Core/action.h"
    #include "../../../include/odfaeg/Core/actionMap.h"
    using namespace std;
    namespace odfaeg {
    Action::Action (EVENT_TYPE type) : type(type) {
        leaf = true;
        pressed = false;
        switch (type) {
            case CLOSED :
                startEvent.type = sf::Event::Closed;
                break;
            case RESIZED :
                startEvent.type = sf::Event::Resized;
                break;
            case LOST_FOCUS :
                startEvent.type = sf::Event::LostFocus;
                break;
            case GAIGNED_FOCUS :
                startEvent.type = sf::Event::GainedFocus;
                break;
            case TEXT_ENTERED :
                startEvent.type = sf::Event::TextEntered;
                break;
            case MOUSE_WHEEL_MOVED :
                startEvent.type = sf::Event::MouseWheelMoved;
                break;
            case MOUSE_MOVED :
                startEvent.type = sf::Event::MouseMoved;
                break;
            case MOUSE_ENTERED :
                startEvent.type = sf::Event::MouseEntered;
                break;
            case MOUSE_LEFT :
                startEvent.type = sf::Event::MouseEntered;
                break;
            case JOYSTICK_MOVED :
                startEvent.type = sf::Event::MouseLeft;
                break;
            case JOYSTICK_CONNECTED :
                startEvent.type = sf::Event::JoystickConnected;
                break;
            case JOYSTICK_DISCONNECTED :
                startEvent.type = sf::Event::JoystickDisconnected;
                break;
        }
        is_not = false;
    }
    Action::Action (EVENT_TYPE type, sf::Keyboard::Key key) : type(type) {
        leaf = true;
        pressed = false;
        switch (type) {
        case KEY_PRESSED_ONCE :
            startEvent.type = sf::Event::KeyPressed;
            startEvent.key.code = key;
            break;
        case KEY_HELD_DOWN :
            startEvent.type = sf::Event::KeyPressed;
            startEvent.key.code = key;
            break;
        case KEY_RELEASED :
            startEvent.type = sf::Event::KeyReleased;
            startEvent.key.code = key;
            break;
        }
        is_not = false;
    }
    Action::Action (EVENT_TYPE type, sf::Mouse::Button button) : type(type) {
        leaf = true;
        pressed = false;
        switch (type) {
            case MOUSE_BUTTON_PRESSED_ONCE :
                startEvent.type = sf::Event::MouseButtonPressed;
                startEvent.mouseButton.button = button;
                break;
            case MOUSE_BUTTON_HELD_DOWN :
                startEvent.type = sf::Event::MouseButtonPressed;
                startEvent.mouseButton.button = button;
                break;
            case MOUSE_BUTTON_RELEASED :
                startEvent.type = sf::Event::MouseButtonReleased;
                startEvent.mouseButton.button = button;
                break;
        }
        is_not = false;
    }
    Action::Action(const Action& other) {
        leaf = other.leaf;
        pressed = other.pressed;
        startEvent = other.startEvent;
        is_not = other.is_not;
        leftChild = std::make_unique<Action>(*other.leftChild);
        rightChild = std::make_unique<Action>(*other.rightChild);
        comparator = other.comparator;
        pressed = other.pressed;
        type = other.type;
    }
    /*Action (EVENT_TYPE type, sf::Joystick::Button button) : type(type) {
        cptype = NONE;
        switch (type) {
            case JOYSTICK_BUTTON_PRESSED_ONCE :
                startEvent.type = sf::Event::MouseButtonPressed;
                startEvent.joystickButton.button = button;
                break;
            case JOYSTICK_BUTTON_HELD_DOWN :
                startEvent.joystickButton.button = button;
                break;
            case JOYSTICK_BUTTON_RELEASED :
                startEvent.type = sf::Event::MouseButtonReleased;
                startEvent.joystickButton.button = button;
                break;
        }
    }*/
    bool Action::andComparator (std::unique_ptr<Action>& a1, std::unique_ptr<Action>& a2) {
        return a1->isTriggered() && a2->isTriggered();
    }
    bool Action::orComparator (std::unique_ptr<Action>& a1, std::unique_ptr<Action>& a2) {
        return a1->isTriggered() || a2->isTriggered();
    }
    bool Action::xorComparator (std::unique_ptr<Action>& a1, std::unique_ptr<Action>& a2) {
        return a1->isTriggered() | a2->isTriggered();
    }
    void Action::operator! () {
        if (!is_not)
            is_not = true;
        else
            is_not = false;
    }
    std::unique_ptr<Action> Action::operator| (Action &other) {
        std::unique_ptr<Action> result = std::make_unique<Action>(COMBINED_WITH_XOR, *this, other);
        return result;
    }
    std::unique_ptr<Action> Action::operator|| (Action &other) {
        std::unique_ptr<Action> result = std::make_unique<Action>(COMBINED_WITH_XOR, *this, other);
        return result;
    }
    std::unique_ptr<Action> Action::operator&& (Action &other) {
        std::unique_ptr<Action> result = std::make_unique<Action>(COMBINED_WITH_XOR, *this, other);
        return result;
    }
    bool Action::isTriggered () {
        vector<sf::Event> events = Command::getEvents();
        if (leaf) {
            if (type == KEY_HELD_DOWN && !is_not) {
                return sf::Keyboard::isKeyPressed(startEvent.key.code);
            }
            if (type == KEY_HELD_DOWN && is_not) {
                return !sf::Keyboard::isKeyPressed(startEvent.key.code);
            }
            if (type == MOUSE_BUTTON_HELD_DOWN && !is_not) {
                return sf::Mouse::isButtonPressed(startEvent.mouseButton.button);
            }
            if (type == MOUSE_BUTTON_HELD_DOWN && is_not) {
                return !sf::Mouse::isButtonPressed(startEvent.mouseButton.button);
            }
            /*else if (type == JOYSTICK_BUTTON_HELD_DOWN)
                return sf::Joystick::isButtonPressed(startEvent.joystickButton.button);*/
            for (unsigned int i = 0; i < events.size(); i++) {
                if (!is_not && !pressed) {
                    return equalEvent(events[i], startEvent);
                } else if (is_not) {
                    return !equalEvent(events[i], startEvent);
                } else {
                    return false;
                }
            }
     
     
        } else {
            return comparator(std::ref(this->leftChild), std::ref(this->rightChild));
        }
    }
    Action::Action (EVENT_TYPE type, Action leftChild, Action rightChild)  {
        leaf = false;
        this->type = type;
        this->leftChild = std::make_unique<Action>(leftChild);
        this->rightChild = std::make_unique<Action>(rightChild);
        is_not = false;
        pressed = false;
        if (type == COMBINED_WITH_AND) {
            comparator = std::bind(&Action::andComparator, this, std::ref(this->leftChild), std::ref(this->rightChild));
        } else if (type == COMBINED_WITH_OR) {
            comparator = std::bind(&Action::orComparator, this, std::ref(this->leftChild), std::ref(this->rightChild));
        } else {
            comparator = std::bind(&Action::xorComparator, this, std::ref(this->leftChild), std::ref(this->rightChild));
        }
    }
     
    bool Action::equalEvent (sf::Event event, sf::Event other) {
        if (event.type != other.type)
            return false;
        if (event.type == sf::Event::Resized) {
            return event.size.width == other.size.width && event.size.height == other.size.height;
        }
        if (event.type == sf::Event::TextEntered) {
            return event.text.unicode == other.text.unicode;
        }
        if (event.type == sf::Event::KeyPressed || event.type == sf::Event::KeyReleased) {
            if (event.type == sf::Event::KeyPressed && event.key.code == other.key.code)
                pressed = true;
            return event.key.code == other.key.code;
        }
        if (event.type == sf::Event::MouseWheelMoved) {
            return event.mouseWheel.delta == other.mouseWheel.delta;
        }
        if (event.type == sf::Event::MouseButtonPressed || event.type == sf::Event::MouseButtonReleased) {
            if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == other.mouseButton.button)
                pressed = true;
            return event.mouseButton.button == other.mouseButton.button;
        }
        if (event.type == sf::Event::MouseMoved) {
            return event.mouseMove.x == other.mouseMove.x && event.mouseMove.y == other.mouseMove.y;
        }
        if (event.type == sf::Event::JoystickButtonPressed || event.type == sf::Event::JoystickButtonReleased) {
            return event.joystickButton.joystickId == other.joystickButton.joystickId
                && event.joystickButton.button == other.joystickButton.button;
        }
        if (event.type == sf::Event::JoystickMoved) {
            return event.joystickMove.joystickId == other.joystickMove.joystickId
                && event.joystickMove.position == other.joystickMove.position;
        }
        return false;
    }
    void Action::setPressed(sf::Event event, bool pressed) {
        if (!leaf) {
            leftChild->setPressed(event, false);
            rightChild->setPressed(event, false);
        } else {
            if ((event.type == sf::Event::KeyReleased && startEvent.type == sf::Event::KeyPressed && event.key.code == startEvent.key.code) ||
                (event.type == sf::Event::MouseButtonReleased && startEvent.type == sf::Event::MouseButtonPressed && event.mouseButton.button == startEvent.mouseButton.button)) {
                this->pressed = pressed;
            }
        }
    }
    bool Action::containsEvent(sf::Event& event) {
        if (!leaf) {
            return leftChild->containsEvent(event) || rightChild->containsEvent(event);
        } else {
            return Command::equalEvent(event, startEvent);
        }
    }
    void Action::getEvents(std::vector<sf::Event>& events) {
        if (!leaf) {
            leftChild->getEvents(events);
            rightChild->getEvents(events);
        } else {
            events.push_back(startEvent);
        }
    }
    Action& Action::operator=(const Action& other) {
        leaf = other.leaf;
        pressed = other.pressed;
        startEvent = other.startEvent;
        is_not = other.is_not;
        leftChild = std::make_unique<Action>(*other.leftChild);
        rightChild = std::make_unique<Action>(*other.rightChild);
        comparator = other.comparator;
        pressed = other.pressed;
        type = other.type;
        return *this;
    }
    }
    Je copie l'action et je la met dans un std::unique_ptr.
    Dernière modification par Invité ; 18/09/2014 à 20h17.

  5. #25
    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
    Citation Envoyé par mintho carmo Voir le message
    Ce qui revient à faire un compteur de référence, donc shared_ptr...

    Pour le delete, comme je l'ai déjà dit, le problème n'est pas que l'observateur fasse un delete (ça ne serait plus un observateur), mais que le propriétaire fasse un delete alors qu'un observateur utilise la ressource (sauf à faire un compteur de référence)
    Ou bien juste faire une application intelligemment. Dans le parent qui lance le thread, tu attends que le 2° thread qu'il a lancé ait fini avant de détruire les ressources.
    Vouloir prendre en compte "oui mais si un jour un utilisateur veut utiliser un 3° thread, oui mais si..." c'est bien, mais revenir sur terre sur son cas concret et y répondre c'est un bon début.
    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.

  6. #26
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    393
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 393
    Points : 685
    Points
    685
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Ou bien juste faire une application intelligemment. Dans le parent qui lance le thread, tu attends que le 2° thread qu'il a lancé ait fini avant de détruire les ressources.
    Vouloir prendre en compte "oui mais si un jour un utilisateur veut utiliser un 3° thread, oui mais si..." c'est bien, mais revenir sur terre sur son cas concret et y répondre c'est un bon début.
    L'aggressivité n'a jamais permit de renforcer une argumentation...

    Quand tu lances un thread, tu as envie qu'il soit bloquant ? Si le thread travaille plusieurs minutes, il n'est pas question de faire un joint pour attendre qu'il ait fini avant de libérer la ressource

    Et bien sûr que l'on va parler du "si un jour un utilisateur veut utiliser un 3° thread". J'ai donné un exemple de code minimaliste pour expliquer pourquoi le problème ne venait pas de l'observateur qui pourrait effacer la ressource, mais de savoir quand le propriétaire peut le faire. Avec un seul thread lancé, on est dans le cas d'un propriétaire unique, on peut transférer la responsabilité (par exemple, un thread pour la lecture et écriture de fichier, il n'aura plus besoin d'avoir la responsabilité des données lu, il pourra donner la propriété)

    Dans une situation où l'on a plusieurs observateurs (avec ou sans plusieurs threads, le problème se posera pour le thread observateur si la ressource est partagée avec un thread et est utilisée dans la thread propriétaire), on devra partager la ressource et le coup du "tu attends que le 2° thread qu'il a lancé ait fini avant de détruire les ressources" sera encore plus problématique.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Ressource r;
    thread(use_ressource, &r);
    use_ressource2(r);
    // quand supprimer r ?
    ou avec 2 threads

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Ressource r;
    thread(use_ressource, &r
    thread(use_ressource2, &r);
    // quand supprimer r ?
    Dans tous les cas, tu n'as pas forcement envie que l'appel des threads soit bloquant, tu ne sais pas quand tu peux supprimer la ressource

    Un autre exemple classique, c'est une classe de rendu, qui garde des observateurs sur des ressources pour pouvoir les afficher et les utilises dans un thread interne (donc impossible de savoir pour le thread principal quand elles sont utilisées ou non). Bien sûr, le thread parent a besoin d'avoir accès aux ressources pour les mettre à jour. Lorsqu'il n'a plus besoin d'une ressource, il va demander sa détruction, mais celle-ci ne pourra pas être effective tant que le rendu en a encore besoin

    C'est en fait une problématique classique et il y a pas mal de solution (sans sahred_ptr) qui ont été développé avec le temps. Mais au final, ces implémentations utilisent en interne un compteur de référence, ce qui est le boulot de shared_ptr (ou un simple bool s'il n'y a qu'un observateur, mais l'idée est la même)

    L'idéal sera d'essayer de ne pas partager une ressource (surtout que cela pose des problèmes d'accès concurents), mais si on doit le faire, le couple unique_ptr + * (ou & ou weak_unique_ptr) sera une mauvaise solution à mon sens.

  7. #27
    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
    Citation Envoyé par mintho carmo Voir le message
    L'idéal sera d'essayer de ne pas partager une ressource (surtout que cela pose des problèmes d'accès concurents), mais si on doit le faire, le couple unique_ptr + * (ou & ou weak_unique_ptr) sera une mauvaise solution à mon sens.
    ... car on a identifier que la ressource pouvait être détruite par l'unique_ptr pendant que l'observateur l'utilisait.
    C'est probablement l'utilisation du mot observer pour un shared_ptr qui me gène un peu, mais avec l'explication c'est plus clair

  8. #28
    Invité
    Invité(e)
    Par défaut
    Mwai non même sans les std::unique_ptr je me retrouve toujours avec ce crash ici :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Action& Action::operator| (Action &other) {
        std::unique_ptr<Action> result = std::make_unique<Action>(COMBINED_WITH_XOR, *this, other);
        return *result;
    }
    Action& Action::operator|| (Action &other) {
        std::unique_ptr<Action> result = std::make_unique<Action>(COMBINED_WITH_XOR, *this, other);
        return *result;
    }
    Action& Action::operator&& (Action &other) {
        std::unique_ptr<Action> result = std::make_unique<Action>(COMBINED_WITH_XOR, *this, other);
        return *result;
    }

    Et c'est depuis que j'utilise gcc4.9 on dirait.
    Dernière modification par Invité ; 19/09/2014 à 12h55.

  9. #29
    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
    Citation Envoyé par Lolilolight Voir le message
    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Action& Action::operator| (Action &other) {
        std::unique_ptr<Action> result = std::make_unique<Action>(COMBINED_WITH_XOR, *this, other);
        return *result;
    }

    Ça n'a pas de sens de retourner une référence sur l'objet tenu par unique_ptr, retourne directement l'unique_ptr pour le déplacer. À la fin du bloc, ton unique_ptr est détruit et ta référence est invalide.

  10. #30
    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
    Citation Envoyé par mintho carmo Voir le message
    Quand tu lances un thread, tu as envie qu'il soit bloquant ? Si le thread travaille plusieurs minutes, il n'est pas question de faire un joint pour attendre qu'il ait fini avant de libérer la ressource
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main() {
    Thread m1;
    Thread m2;
    m1.FaitSaVie();
    m2.FaitSaVie();
    while (run) {
    // l'application fait aussi sa vie
    }
    m1.join();
    m2.join();
    // tu supprimes sans aucun risque
    }
    Ca relève pas du défi amha.
    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.

  11. #31
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    393
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 393
    Points : 685
    Points
    685
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Ca relève pas du défi amha.
    Oui, sur un cas aussi simple que des ressrouces allouées au lancement de l'application et libéré à la fin, on trouvera des solutions. On pourra aussi faire la remarque que si le thread alloue lui aussi des ressources, cela impose qu'il ne sera pas détruit (et donc libérera ses propres ressources internes) avant la fin du problème. Et pour ce problème aussi on pourra trouver des solutions.

    On utilise des ressources et des threads bien avant l'apparition de shared_ptr/weak_ptr.

    Mon propos était surtout de soulever une problématique posée par unique_ptr/* (ou & ou weak_unique_ptr) et que shared_ptr/weak_ptr peut être une solution intéressante (que perso je conseille en premier par rapport à la première solution dans le cas de plusieurs observateurs). Maintenant, si tu préfères une solution n'utilisant pas shared_ptr, que tu as vérifié que ta solution ne présente pas la problématique que j'ai essayé d'expliquer, c'est très bien. C'est ton code, c'est toi qui décide de la solution

  12. #32
    Invité
    Invité(e)
    Par défaut
    Mmmm, j'ai changé mon code et maintenant il utilise des std::unique_ptr.

    Mon framework initialise tout au début de l'application et libère tout à la fin de l'application donc, il n'y a pas de problème, même lors de l'utilisation de plusieurs thread.

    Cependant, je trouve ça moche de forcer l'utilisateur de la bibliothèque à devoir faire cela au cas ou la classe deviendrait propriétaire :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    InputSystem::getListener().connect("A command", std::move(command));
    Ou bien avec les pointeurs, forcer l'utilisateur à devoir faire un std::make_unique ou un std::make_shared.

    J'aimerais bien me passer du std::move lors de l'utilisation de la bibliothèque mais apparemment la seule solution qui marche vraiment pour faire ça c'est du perfect forwarding avec des templates.
    Donc bon finalement j'ai fais à chaque fois une copie que je passe à std::make si c'est un pointeur ou à la variable membre si ce n'est pas un pointeur.

Discussions similaires

  1. Réponses: 19
    Dernier message: 29/09/2014, 17h12
  2. Réponses: 2
    Dernier message: 04/08/2014, 13h43
  3. Exceptions, quand les utiliser
    Par JuTs dans le forum Général Dotnet
    Réponses: 6
    Dernier message: 13/05/2007, 15h27
  4. [Smarty] Utilité ? Quand les utiliser ?
    Par Xunil dans le forum Bibliothèques et frameworks
    Réponses: 25
    Dernier message: 28/11/2006, 17h08
  5. fonctions et classes... quand les utiliser ?
    Par fastmanu dans le forum Langage
    Réponses: 6
    Dernier message: 03/04/2006, 00h39

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