Partage
  • Partager sur Facebook
  • Partager sur Twitter

étude de noexcept sur exemples

C++

Sujet résolu
    31 janvier 2019 à 18:28:36

    Bonjour OC,

    je suis sur la page

    https://en.cppreference.com/w/cpp/language/noexcept

    J'ai compris le principe général des exceptions.

    Et j'ai des difficultés à comprendre le résultat des lignes en fonction des destructeurs, et move constructeur :

    << "Is ~T() noexcept? " << noexcept(std::declval<T>().~T()) << '\n'
               // note: the following tests also require that ~T() is noexcept because
               // the expression within noexcept constructs and destroys a temporary
               << "Is T(rvalue T) noexcept? " << noexcept(T(std::declval<T>())) << '\n'
               << "Is T(lvalue T) noexcept? " << noexcept(T(t)) << '\n'
               << "Is U(rvalue U) noexcept? " << noexcept(U(std::declval<U>())) << '\n'
               << "Is U(lvalue U) noexcept? " << noexcept(U(u)) << '\n'  
               << "Is V(rvalue V) noexcept? " << noexcept(V(std::declval<V>())) << '\n'
               << "Is V(lvalue V) noexcept? " << noexcept(V(v)) << '\n';  

    ainsi que 

    la différence de comportement à noexcept des 3 classes :

    class T{
    public:
      ~T(){} // dtor prevents move ctor
             // copy ctor is noexcept
    };
    class U{
    public:
      ~U(){} // dtor prevents move ctor
             // copy ctor is noexcept(false)
      std::vector<int> v;
    };
    class V{
    public:
      std::vector<int> v;
    };

    En fonction par exemple de la présence du destructeur dans U et V. Pourquoi cela change ?

    Pouvez-vous m'aider pour comprendre ce qu'il se passe en détails ?

    Par avance merci


    -
    Edité par pseudo-simple 31 janvier 2019 à 18:38:27

    • Partager sur Facebook
    • Partager sur Twitter
      31 janvier 2019 à 21:16:49

      • Définir un destructeur supprime le constructeur de déplacement implicite.
      • Le constructeur de copie de std::vector n'est pas noexcept.
      • Partager sur Facebook
      • Partager sur Twitter
        31 janvier 2019 à 22:26:24

        Ok, je réfléchis et je commence à comprendre. J'ai alors 3 questions :

        1) Est-ce que le constructeur de déplacement implicite est toujours noexcept ?

        2) De plus, dans les deux lignes suivantes :

        << "Is T(rvalue T) noexcept? " << noexcept(T(std::declval<T>())) << '\n'
               
                   << "Is U(rvalue U) noexcept? " << noexcept(U(std::declval<U>())) << '\n'
                 


        je cherche la bonne justification :

        Dans T comme dans U, on définit explicitement le destructeur, donc le constructeur par mouvement implicite est supprimé. Donc en principe, dans ces deux classes, on a pas de constructeur par mouvement. Or pour T, on obtient que la première des deux lignes donne un true, alors que la deuxième ligne pour U, donne un false.

        Or dans les deux cas, c'est bien une construction par mouvement (objet temporaire) et dans les deux cas, le destructeur est explicitement déclaré. Et pourtant nulle part, on ne définit manuellement de constructeur par mouvement, donc comment peut-on déduire si le résultat est noexcept ou non ?

        EDIT :

        3) en réfléchissant à l'exemple avec V, même là, je ne comprends pas :

        Is V(rvalue V) noexcept? " << noexcept(V(std::declval<V>())) << '\n'
                   << "Is V(lvalue V) noexcept? " << noexcept(V(v)) << '\n';  

        on obtient que le constructeur par mouvement est activé car pas de définition de destructeur. Et dans le premier cas, on obtient true , malgré la présence du vector et false après. En plus, en ++11/14, le constructeur par déplacement n'est pas noexcept d'après la doc.

        Merci

        -
        Edité par pseudo-simple 31 janvier 2019 à 23:49:25

        • Partager sur Facebook
        • Partager sur Twitter
          31 janvier 2019 à 23:38:50

          > Est-ce que le constructeur de déplacement implicite est toujours noexcept ?

          Non, il l'est seulement si le constructeur de chaque membre est noexcept. Et ce pour toutes les fonctions implicites d'une classe: constructeur et opérateur = de déplacement et de copie + destructeur.

          • Partager sur Facebook
          • Partager sur Twitter
            31 janvier 2019 à 23:42:29

            Pouvez-vous m'aider pour les 2 autres questions ?

            Merci

            -
            Edité par pseudo-simple 31 janvier 2019 à 23:44:21

            • Partager sur Facebook
            • Partager sur Twitter
              1 février 2019 à 10:19:33

              cette dernière réponse ne m'a pas aidé à répondre aux deux autres questions pour l'instant.

              Les deux cas avec V m'échappent, car à priori il n'y a pas de destrcuteur explicite donc le constructeur par déplacement implicite est activé.

              Or la contruction par déplacement d'un vector peut entraîner une exception en C++11. Donc la construction par déplacement à partir d'une rvalue devrait , selon moi, donner un false, et ça donne un true.

              Alors que la construction par copie, n'est pas, dans ce cas, noexcept.

              -
              Edité par pseudo-simple 1 février 2019 à 14:34:24

              • Partager sur Facebook
              • Partager sur Twitter
                1 février 2019 à 16:42:18

                > à priori il n'y a pas de destrcuteur explicite donc le constructeur par déplacement implicite est activé.

                Oui.

                > Or la contruction par déplacement d'un vector peut entraîner une exception en C++11.

                1) Tu n'as pas précisé le standard que tu utilises.

                2) Je ne le savais pas et libstdc++ force le noexcept quand même. Ce n'est probablement pas valide en C++11, même si les cas pathologiques sont extrêmement rares. Ce que je ne comprends pas, c'est pourquoi le noexcept ne dépend pas du constructeur de déplacement de l'allocateur. À moins que celui-ci doit être noexcept.

                -
                Edité par jo_link_noir 1 février 2019 à 16:49:22

                • Partager sur Facebook
                • Partager sur Twitter
                  1 février 2019 à 18:17:34

                  Bonjour Monsieur

                  pouvez-vous préciser ce que vous voulez dire par rapport au déplacement de l'allocateur ?

                  Pour l'instant, par rapport au cas de de T , U et V, je n'ai pas une explication bien claire qui me permette d'expliquer chaque cas.

                  J'ai essayé plusieurs explications, mais il y a des contradictions comme vous avez vu dans mes messages précédents.

                  Par exemple, d'après la doc, la construction par déplacement d'un std::vector en C++11, peut lancer une exception. Donc le premier V ne devrait pas être noexcept d'après ce que je sais actuellement. Or il l'est.

                  Je vous remercie par avance

                  -
                  Edité par pseudo-simple 1 février 2019 à 19:06:26

                  • Partager sur Facebook
                  • Partager sur Twitter
                    1 février 2019 à 21:39:51

                    > pouvez-vous préciser ce que vous voulez dire par rapport au déplacement de l'allocateur ?

                    Ça ne servira qu'à t'embrouiller, alors non.

                    > Par exemple, d'après la doc, la construction par déplacement d'un std::vector en C++11, peut lancer une exception. Donc le premier V ne devrait pas être noexcept [...]

                    Je le répète, il l'est pour libstdc++.

                    • Partager sur Facebook
                    • Partager sur Twitter
                      1 février 2019 à 21:58:57

                      En C++17 oui probablement d'après la doc.

                      PAs en C++11.

                      Or c'est avec ce dernier standard que je compile.

                      Dans ce cas, pourquoi alors avec U construit par déplacement avec une rvalue, ce n'est pas noexcept ?

                      Le constructor par déplacement est désactivé. Donc pourquoi n'est-ce pas noexcept ?

                      Un autre point que je ne saisis , c'est que dans les deux premiers exemples, comme le move constructeur est désactivé, comment peut-on faire appel à un constructeur comme avec T et U alors que ils sont désactivés ? Je veux dire : quelle est la fonction appelée puisque le constructeur par déplacement est désactivé ?

                      Merci par avance

                      -
                      Edité par pseudo-simple 1 février 2019 à 23:00:28

                      • Partager sur Facebook
                      • Partager sur Twitter
                        1 février 2019 à 22:59:21

                        > En C++17 oui probablement d'après la doc. PAs en C++11.

                        Je vais le dire autrement: libstdc++ n'en a rien à faire du standard :)

                        > Dans ce cas, pourquoi alors avec U construit par déplacement avec une rvalue, ce n'est pas noexcept ?

                        J'y ai déjà répondu dans mon premier message.

                        > Le constructor par déplacement est désactivé. Donc pourquoi n'est-ce pas noexcept ?

                        Depuis quand le constructeur de copie est noexcept ?

                        • Partager sur Facebook
                        • Partager sur Twitter
                          1 février 2019 à 23:26:29

                          si je comprends :

                          Avec le cas de U :

                          Est-ce que vous sous-entendez qu'une règle serait que si le constructeur par déplacement est désactivé et qu'aucun constructeur par déplacement n'est explicitement défini, alors c'est automatiquement le constructeur par copie qui est utilisé , même si l'argument qui lui est donné est une rvalue ?

                          car c'est ce que vous avez l'air de suggérer avec le premier cas sur U.

                          Si c'st cela, pouvez-vous me renvoyer vers une page qui explique ce mécanisme ?

                          Merci par avance

                          -
                          Edité par pseudo-simple 1 février 2019 à 23:49:31

                          • Partager sur Facebook
                          • Partager sur Twitter
                            2 février 2019 à 0:28:54

                            La page concernant le constructeur de déplacement.

                            Et sinon, l'appel d'un constructeur suit n'importe quel appel de fonction. Donc je ne vois pas quel est le problème à appeler une fonction prenant une T const& avec une rvalue.

                            -
                            Edité par jo_link_noir 2 février 2019 à 0:31:30

                            • Partager sur Facebook
                            • Partager sur Twitter
                              2 février 2019 à 2:28:08

                              jo_link_noir a écrit:

                               appel de fonction. Donc je ne vois pas quel est le problème à appeler une fonction prenant une T const& avec une rvalue.

                              -
                              Edité par jo_link_noir il y a environ 1 heure 


                              Pourriez-vous expliciter ou la corriger pour que votre réponse m'aide à répondre à ma question ?

                              Je précise : par exemple des fils de discussion passés, on ne peut pas passer une rvalue à une fonction dont la signature est du genre S f(T& t), c'est-à-dire où la fonction attend une value passée par référence.

                              Je vous en remercie.

                              -
                              Edité par pseudo-simple 2 février 2019 à 2:43:52

                              • Partager sur Facebook
                              • Partager sur Twitter
                                2 février 2019 à 2:50:50

                                YES, man a écrit:

                                jo_link_noir a écrit:

                                 appel de fonction. Donc je ne vois pas quel est le problème à appeler une fonction prenant une T const& avec une rvalue.

                                -
                                Edité par jo_link_noir il y a environ 1 heure 


                                Pourriez-vous expliciter ou la corriger pour que votre réponse m'aide à répondre à ma question ?

                                Je précise : par exemple des fils de discussion passés, on ne peut pas passer une rvalue à une fonction dont la signature est du genre S f(T& t), c'est-à-dire où la fonction attend une value passée par référence.

                                Je vous en remercie.

                                La réponse est dans la réponse.

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  2 février 2019 à 3:36:58

                                  Ok, Je pense que à partir de maintenant, je devrai donc admettre que l'on peut passer une rvalue à  une fonction dont la signature est en S f(T const &t ). J'aimerais bien comprendre comment on le justifie. Est-ce parce que une rvalue n'est pas faire pour être modifiée et que du coup, on peut la transmettre à une fonction avec en paramètre const & ?

                                  J'ai deux autres questions : 

                                  1) quelle est différence entre le standard de mon C++ (par ex C++11) et libstdc++ ?

                                  2) Je viens d'aller dans les options de mon compilateur pour vérifier si j'ai l'option libstdc++ et j'ai vu que l'option "static libstdc++" est désactivée.

                                  Comment expliquer que malgré cela, mes constructeurs par déplacement sont noexcept ?

                                  Merci

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    2 février 2019 à 5:27:39

                                    YES, man a écrit:

                                    je devrai donc admettre que l'on peut passer une rvalue à  une fonction dont la signature est en S f(T const &t ).

                                    Chose qu'on t'a déjà dit il y a plusieurs mois https://openclassrooms.com/forum/sujet/c-scott-meyers-transmission-parfaite?page=2#message-92726246

                                    YES, man a écrit:

                                    1) quelle est différence entre le standard de mon C++ (par ex C++11) et libstdc++ ?

                                    2) Je viens d'aller dans les options de mon compilateur pour vérifier si j'ai l'option libstdc++ et j'ai vu que l'option "static libstdc++" est désactivée.

                                    Comment expliquer que malgré cela, mes constructeurs par déplacement sont noexcept ?

                                    Merci

                                    Le standard est un document qui décrit comment cela devrait fonctionner. La libstdc++ est une des implémentations de la bibliothèque standard. Cela arrive (très souvent) qu'une implémentation ne suive pas exactement le standard.

                                    YES, man a écrit:

                                    2) Je viens d'aller dans les options de mon compilateur pour vérifier si j'ai l'option libstdc++ et j'ai vu que l'option "static libstdc++" est désactivée.

                                    Ca veut dire que l'implémentation que tu utilises active noexcept sur les constructeurs de déplacement.

                                    Voilà pourquoi on n'étudie pas un langage avec le standard, mais avec un cours. Parce que lire le standard n'est pas important et ce n'est pas un apprentissage efficace. On lit le standard quand on maitrise le langage et qu'on veut étudier les détails avancés.

                                    Les C++ core guidelines recommandent (de mémoire, à vérifier) que les moves soient noexcept. Les développeurs de la bibliothèque standard ont probablement considéré que c'est un "bug" de la norme de ne pas avoir fait cela pour std::vector et ils ont appliqués rétroactivement ce point du standard.

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      2 février 2019 à 6:26:08

                                      Ok, merci je comprends.

                                      Toujours par rapport à noexcept, il est dit que la plupart des fonctions sont neutres envers les exceptions.

                                      Or récemment, j'ai lu un code tout simple avec une fonction qui n'était pas  noexcept, et dès que l'exécution a lancé l'excéption, l'exécution s'est arrêtée avec le message "called terminate...."

                                      Manifestement, cette fonction n'était pas neutre envers cette exception puisque l'exécution s'est arrêtée ?

                                      Donc, qu'est-ce que ça veut dire "être neutre par rapport aux exceptions" ?

                                      Merci par avance

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        2 février 2019 à 7:06:57

                                        Je suppose que cela vient de "Effective Modern C++"...

                                        Le terme en anglais est "exception-neutrality". (Hors suet : c'est le problème d'utiliser des traductions non officielles ou tout au moins pas dans les usages : c'est difficile de faire des recheches sur le terme. A mon sens, il faut indiquer les termes anglais quand on fait des "premieres" traductions).

                                        Une définition (personnelle) simple (simpliste?) : c'est une fonction qui transmet une exception, sans la modifier.

                                        Une fonction noexcept n'est pas neutre, puisque l'exception n'est pas propagée.

                                        -
                                        Edité par gbdivers 2 février 2019 à 17:41:57

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          2 février 2019 à 11:23:09

                                          Avant de poster mon message, j'avais noté que la traduction est bancale et j'avais saisi que l'auteur veut mettre en lumière la différence entre être noexcept, et être neutre par rapport aux exceptions.

                                          Ce que je voulais in fine, c'était comprendre la définition de exception-neutrality. Donc merci, ça m'éclaire : donc une fonction, du genre

                                          int f(){
                                          
                                          if {...}
                                          
                                          throw 24;
                                          
                                          }



                                          est-elle exception-neutral par exemple ? (puisqu'elle n'est pas noexcept ?)

                                          Je ne vois pas en quoi, elle ne ferait que transmettre une exception alors qu'elle l'a émise.

                                          Si mon exemple n'est pas bien choisi, pouvez-vous m'indiquer un exemple de fonction exception-neutral ?

                                          Je vous remercie.

                                          -
                                          Edité par pseudo-simple 2 février 2019 à 12:45:22

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            2 février 2019 à 13:14:07

                                            Salut,

                                            On va faire simple : toute fonction qui n'est pas explicitement noexcept est une fonction qui fait preuve de neutralité vis à vis des exceptions.

                                            Pourquoi? me demanderas tu.  Hé bien tout simplement parce qu'elle accepte de faire appel à une fonction qui risque elle-même de lui transmettre une exception et qu'elle accepte de ce simple fait de transmettre l'exception à la fonction qui l'aura appelée.

                                            Maintenant, que la fonction crée l'exception elle-même, ou qu'elle se "contente" de transmettre une exception qui lui aura été transmise par une fonction à laquelle elle fait appel n'a que peu d'intérêt, parce que le résultat sera toujours le même : quelle que soit l'origine d'une exception éventuelle, le compilateur laissera la fonction la transmettre à la fonction appelante.

                                            void doSomething(){
                                                /* doSomething n'est pas noexcept.
                                                 * on se fout pas mal de la raison pour laquelle cela
                                                 * arriverait : elle accepte de transmettre une exception
                                                 * si elle survient
                                                 */
                                            }
                                            void bar(){
                                                /* Même chose ... */
                                                doSomething(); /* transmet en cas de besoin l'éventuelle exception
                                                                * transmise par doSomething();
                                                if(!test){
                                                    /* ou crée peut être sa propre exception ...
                                                     * qui sera forcément transmise à la fonction appelante
                                                     */
                                                    throw std::runtime_error("exception"); 
                                                }
                                            
                                            }
                                            void truc() noexcept(true){
                                                /* nous avons la garantie que truc ne transmettra 
                                                 * JAMAIS d'exception à la fonction qui l'appelle
                                                 */
                                            }
                                            void foo(){
                                                truc(); /* aucun risque d'avoir une exception ici */
                                                bar();  /* par contre, bar peut transmettre à foo()
                                                         * 1- une exception "de son propre cru"
                                                         * 2- n'importe quelle exception transmise --
                                                         * quelle qu'en soit la raison -- par doSomething()
                                                         */ 
                                            }
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                              2 février 2019 à 14:52:23

                                              Bonjour Koala01,

                                              après réflexion sur votre message, j'en déduis donc que si la fonction foo() était elle-même ensuite appelée dans le giron d'une autre fonction f, alors l'exception en question serait renvoyée à f() si elle n'a pas pu être traitée avant dans un catch ?

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                2 février 2019 à 15:20:42

                                                Exactement, c'est le principe même des exceptions : elles remontent la pile d'appel jusqu'à être intercepté par le catch qui va bien.

                                                Et toute fonction qui permet à une exception de remonter la pile d'appel "d'un cran de plus" est -- par définition -- neutre au sujet des exceptions.

                                                Il n'y a que les fonctions explicitement noexcept pour lesquelles le compilateur ne permettra pas à l'exception de remonter.  Et la seule manière dont il puisse s'y prendre, c'est ... de n'autoriser, au niveau des fonctions noexcept, de faire appel qu'à des fonctions qui sont elles aussi noexcept.

                                                L'un dans l'autre, c'est exactement la même logique que celle que l'on observe avec les fonctions membres constantes:

                                                Il est possible d'appeler une fonction membre constante depuis n'importe quelle donnée, qu'elle soit constante ou non; mais seules les fonctions membres qui s'engagent spécifiquement à ne pas modifier l'instance de la classe peuvent être appelées depuis une instance constante.  Et, à pour qu'une fonction membre constante puisse respecter son engagement de ne pas modifier l'instance en cours, le compilateur n'accepte que l'on fasse appel... à des fonctions qui se sont également engagées à ne pas modifier l'instance en question.

                                                Pour faire simple : noexcept indique qu'une fonction s'engage à ne pas transmettre d'exception.  Et, pour qu'elle puisse respecter cet engagement, le compilateur veillera à ce que l'on ne puisse pas appeler de fonction qui n'auraient pas pris le même engagement ;)

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                                  2 février 2019 à 16:14:50

                                                  > Pour faire simple : noexcept indique qu'une fonction s'engage à ne pas transmettre d'exception. Et, pour qu'elle puisse respecter cet engagement, le compilateur veillera à ce que l'on ne puisse pas appeler de fonction qui n'auraient pas pris le même engagement ;)

                                                  Attention, Le compilateur ne fait pas cette vérification car:

                                                  • Ce n'est pas parce qu'une fonction peut lancer des exceptions qu'elle le fera.
                                                  • On peut toujours faire des try/catch et donc capturer les exceptions dans une fonction noexcept.

                                                  Par contre si exception traverse une fonction noexcept, alors un std::terminate est automatiquement appelée.

                                                  -
                                                  Edité par jo_link_noir 2 février 2019 à 16:48:02

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    2 février 2019 à 17:55:43

                                                    koala01 a écrit:

                                                    On va faire simple : toute fonction qui n'est pas explicitement noexcept est une fonction qui fait preuve de neutralité vis à vis des exceptions.

                                                    koala01 a écrit:

                                                    Il n'y a que les fonctions explicitement noexcept pour lesquelles le compilateur ne permettra pas à l'exception de remonter.

                                                    Un peu trop simplifié. La notion d'exception-neutral date d'avant le C++11 et noexcept.

                                                    Une fonction peut ne pas être noexcept et ne pas être exception-neutral pour autant. Un simple try-catch peut modifier l'exception et rendre une fonction non neutre.

                                                    void bar() {
                                                        try {
                                                            foo();
                                                        }
                                                        catch(std::bad_alloc const&) {
                                                            throw std::runtime_error("error");
                                                        }
                                                    }

                                                    Mais la présence d'un try-catch n'est pas suffisant pour dire qu'une fonction n'est pas neutre. 

                                                    void var() { // exception neutral
                                                        try {
                                                            foo();
                                                        }
                                                        catch(std::bad_alloc const&) {
                                                            do_something();
                                                            throw;
                                                        }
                                                    }

                                                    Donc :

                                                    - pas de try-catch du tout = toujours exception neutral

                                                    - noexcept = jamais exception neutral

                                                    - présence d'un try-catch = ça dépend

                                                    @YES, man

                                                    L'exception-neutrality vient des problématiques de exception garantee, c'est à dire les garanties que l'on a quand on utilise les exceptions. (Je me demande si koala ou lmghs n'ont pas écrit un article sur ces garanties ?).

                                                    Quelle est la problématique ? Si tu as un code de gestion des exceptions, par exemple :

                                                    void bar() {
                                                        try {
                                                            do_something();
                                                        }
                                                        catch(std::bad_alloc const&) {
                                                            // gestion de l'exception
                                                        }
                                                    }

                                                    Alors, avec une fonction exception neutral "foo", tu peux écrire :

                                                    void bar() {
                                                        try {
                                                            foo(do_something());
                                                        }
                                                        catch(std::bad_alloc const&) {
                                                            // gestion de l'exception
                                                        }
                                                    }

                                                    et ta gestion des exceptions reste valide.

                                                    Avec une fonction non exception neutral, ta gestion d'exception n'est plus valide.

                                                    Il y a beaucoup à dire sur les garanties que l'on peut apporter sur les exceptions. Je te conseille de te renseigner sur le sujet. Mais dans certains cas (en particulier les classes "utilitaires" de la lib standard comme std::vector, std::unique_ptr, etc), il est très important que les fonctions (membres) soient exception neutral. Cela permet de substituer un code par un autre. Par exemple, imagines que tu veux remplacer un pointeur nu par un pointeur intelligent :

                                                    void foo()
                                                        UneClasse* p = new UneClasse;
                                                    }

                                                    par :

                                                    void foo()
                                                        auto p = std::make_unique<UneClasse>();
                                                    }

                                                    Si std::unique_ptr n'est pas exception neutral, alors cela veut dire que ce changement nécessiterait de devoir changer toute la gestion des exceptions. Avec l'exception neutral, on peut faire ce changement sans problème.

                                                    -
                                                    Edité par gbdivers 2 février 2019 à 18:11:33

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      2 février 2019 à 19:14:50

                                                      Merci à vous tous pour cette série d'exemples et de contre-exemples instructive :

                                                      j'ai quelques questions dessus :

                                                      1)

                                                      Dans le premier exemple :

                                                      void bar() {
                                                          try {
                                                              foo();
                                                          }
                                                          catch(std::bad_alloc const&) {
                                                              throw std::runtime_error("error");
                                                          }
                                                      }

                                                      est-ce que la fonction n'est pas neutre à cause du message "error" qui vient s'aggréger à l'exception et qui donc modifie l'exception  ?

                                                      2) Dans le code :

                                                      void var() { // exception neutral
                                                          try {
                                                              foo();
                                                          }
                                                          catch(std::bad_alloc const&) {
                                                              do_something();
                                                              throw;
                                                          }
                                                      }

                                                      si la fonction do_something() renvoie par hasard une exception, est-ce que cette dernère est-elle nécessairement  rattrapée par un catch potentiel à partir d'une fonction ayant appelée var() ou bien l'exception peut être redéclenchée par throw en personne ?

                                                      Merci par avance

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        2 février 2019 à 19:49:32

                                                        YES, man a écrit:

                                                        est-ce que la fonction n'est pas neutre à cause du message "error" qui vient s'aggréger à l'exception et qui donc modifie l'exception  ?

                                                        "ne pas modifier", on ne peut pas etre plus clair. Ici, le type de l'exception change (bad_alloc -> runtime_error). Mais changer le contenu ou quoi que ce soit, on n'est plus exception neutral.

                                                        YES, man a écrit:

                                                        si la fonction do_something() renvoie par hasard une exception, est-ce que cette dernère est-elle nécessairement  rattrapée par un catch potentiel à partir d'une fonction ayant appelée var() ou bien l'exception peut être redéclenchée par throw en personne ?

                                                        A ton avis ?

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          2 février 2019 à 20:16:24

                                                          pour la deuxième question, je réponds : un catch potentiel d'une fonction ayant appelé var().

                                                          Est-ce le cas ?

                                                          Merci à vous

                                                          -
                                                          Edité par pseudo-simple 2 février 2019 à 20:31:17

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            2 février 2019 à 21:01:10

                                                            Ta question est étrange. Je t'ai expliqué pourquoi on recherche l'exception neutrality, comment cela fonctionne. Tu as tous les éléments pour comprendre.
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            étude de noexcept sur exemples

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                            • Editeur
                                                            • Markdown