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

Discussion :

Vérification des allocations suite à new ?

  1. #1
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 140
    Points : 103
    Points
    103
    Par défaut Vérification des allocations suite à new ?
    Bonjour,

    Je débute plus ou moins avec Qt et je me pose la question de la vérification d'une allocation dynamique.
    Lors de la construction dynamique d'un objet avec new, doit-on vérifier la bonne allocation ? si oui comment sachant que classiquement (en C++ à la grand-papa)
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ...
    // cas où j'ai une gestion des exceptions:
    Object * myObject( new Object() );
    ...
    // cas où je n'ai pas de gestion des exceptions:
    Object * myObject( new( std::nothrow ) Object() );
    // puis test:
    if ( !myObject )
    ...

    Merci pour vos réponses.

  2. #2
    Membre émérite
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Points : 2 834
    Points
    2 834
    Par défaut
    À ce niveau là Qt ne fait pas de différence, on utilise l'opérateur new standard pour créer des objets. Qt n'utilise pas les exceptions, donc pas de comportement particulier non plus à ce niveau là.

    Dans les exemples dans le code Qt ne vérifie pas les allocations de ce que j'en sais, et en C++ certains pensent qu'on ne peut de toute façon pas faire grand chose si l'allocation échoue donc autant crasher. En bref, fais exactement comme tu le ferais en C++ sans Qt.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    De manière générale, tu ne voudras jamais utiliser la version nothrow (noexcept, depuis C++ 11) de new:
    • les cas dans lesquels tu voudrais profiter de cette possibilité sont particulièrement rares (et "tirés par les cheveux")
    • les avantage qu'il y a à tirer profit de la levée d'une exception sont beaucoup trop importants
    • les implications qui découlent du fait que l'allocation dynamique de la mémoire puisse échouer te font entrer dans une logique de programmation défensive qui complexifiera toute ta logique.

    Qt se fout finalement pas mal de savoir si tu as eu recours au new "classique" (comprend : celui qui peut lancer une exception) ou non : pour lui, ce qui importe, c'est que le pointeur représente l'adresse mémoire à laquelle on trouvera un élément donné.

    Par contre, il faut te dire que, chaque tentative de déréférencement d'un pointeur pour lequel tu auras eu recours à la version nothow de new devra impérativement être vérifiée d'un test destiné à t'assurer que le pointeur est bel et bien valide. Si tu dois déréférencer ce pointeur dans 25 fonctions différentes, tu devra le tester dans ... 25 fonctions différentes.

    De son coté, la version "classique" de new simplifie grandement les choses : elle réussi, ou elle lance une exception. Et tu as donc la garantie, si l'exception n'a pas été lancée, que le pointeur représente une adresse mémoire valide.

    Et comme l'a si bien dit ymoreau, si une exception venait à être lancée, il faut te dire que c'est très certainement parce que le système d'exploitation a rencontré un problème pour arriver à allouer la mémoire reçue, si bien que la réaction la plus adéquate est sans doute ... de laisser planter purement et simplement l'application.

    De plus, il faut savoir
    • que Qt met en place un système de "parent / enfants": quand tu détruit un "parent" (par exemple, une fenêtre), la mécanique interne fait en sorte de détruire correctement tous les enfants qu'il contient, ainsi que tous les enfants que les enfants contiennent, et ce jusqu'au "tout dernier arrière petit descendant" qui pourrait exister
    • que delete sur un pointeur nul est garanti (par la norme) comme étant sans effet.

    La conclusion est donc simple : si tu n'as pas une excellente raison de recourir à la version nothrow de new (et je peux t'assurer que ca ne court pas les rues... Perso, en plus de 15 ans de développement, je ne crois pas encore avoir croisé une seule situation dans laquelle cela m'ait servi), tu as très largement intérêt à ne pas l'utiliser.

    Tu arrives visiblement à une étape "cruciale" de ton apprentissage du C++, car tu commences tout doucement à te faire une image relativement précise des différents tenants et aboutissants. Et c'est tout à ton honneur.

    Mais cette étape est particulièrement difficile, parce que le plus gros piège dans lequel tu puisse tomber ( et dans lequel tu viens d'ailleurs de tomber) est de... vouloir réfléchir trop loin, et de te créer toi-même des problèmes que tu aurais pu éviter en continuant à respecter les règles simples que l'on a pu t'apprendre

    Tu en es donc à un point où il est temps de commencer à te répéter comme un mantra :
    Les solutions les plus simples sont les moins compliquées
    heu, pardon, ... où il est tant de te répéter comme un mantra, avant toute décision
    Les solutions les plus simples sont les meilleures
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 140
    Points : 103
    Points
    103
    Par défaut
    Bonjour,

    Merci ymoreau pour ta réponse.

    Merci koala01 pour ta réponse (ta prose... que je lis toujours avec intérêt :-)).

    J'ai certes de bons (ou mauvais mais c'est selon) vieux réflexes appris à force de projets. Mais j'essaie de me soigner :-), notamment en allant plus loin dans la compréhension des mécanismes sous-jacents à la construction dynamique d'objets. Depuis que je fais du C++, il a bien évolué (je ne juge pas du bien ou mal de ces évolutions) mais parfois le dev 'à la grand-papa' est imposé (cela n'est pas l'objet de la discussion).
    Mais finalement et même si c'est un peu hors sujet, lors d'une telle construction :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // ...
    Object * myObject( new( std::nothrow ) Object() );
    if ( !myObject )
    {
        // Stop the program
        return ERROR;
    }
    else
    {
        // Continue the program
    }
    si l'allocation échoue, j'arrête le programme sinon je continue. Si je continue (c'est que l'allocation s'est bien passée) mais même dans ce cas, si je dois déréférencer ce pointeur dans 25 fonctions différentes, je devrai le tester dans ... 25 fonctions différentes ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par MicBeastKiller Voir le message
    lors d'une telle construction :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // ...
    Object * myObject( new( std::nothrow ) Object() );
    if ( !myObject )
    {
        // Stop the program
        return ERROR;
    }
    else
    {
        // Continue the program
    }
    si l'allocation échoue, j'arrête le programme sinon je continue. Si je continue (c'est que l'allocation s'est bien passée) mais même dans ce cas, si je dois déréférencer ce pointeur dans 25 fonctions différentes, je devrai le tester dans ... 25 fonctions différentes ?
    Dans cette configuration bien précise, non, tu ne devras peut être pas tester le pointeur dans les 25 fonction... Mais...

    Le problème est toujours le même : dans quelle mesure peux tu faire confiance à un type pour faire correctement quelque chose lorsqu'il décide pertinemment de faire quelque chose qu'il n'aurait pas du

    En plus, tu double d'un seul coup les chemins d'exécution, et donc les tests pour t'assurer de la validité de ton application. Sans oublier (mais dans une moindre mesure) que le compilateur aura une chance sur deux de mal prédire le chemin qui sera effectivement utilisé.

    en outre, le comportement par défaut de new en cas d'erreur a toujours été de lancer une exception, et ce, depuis que le C++ existe. Mais ce n'est pas son seul attrait : c'est aussi (et sans doute avant tout) d'appeler le constructeur de l'objet pour lequel l'allocation dynamique a été effectuée.

    Tu me diras que new nothrow appelle aussi le constructeur de l'objet, nous sommes bien d'accord. Mais il ne doit être utilisé que si la fonction qui fait appel à new a une bonne raison de ne pas vouloir lancer d'exception (par exemple, si la fonction qui l'appelle est déclarée extern C, afin de pouvoir être appelée depuis un programme écrit en C).

    Or, on est ici dans une section spécifique à Qt, et Qt ne fait absolument rien pour être compatible avec le C (c'est la raison pour laquelle tu as autant de versions des dll de Qt que de compilateurs et de versions de compilateurs). Tu n'auras donc a priori jamais besoin d'utiliser la version nothrow de new dans ce cadre bien précis

    Et même en C++ normal : les cas dans lesquels tu auras recours à l'allocation dynamique de la mémoire (de manière générale) sont déjà limité à une partie seulement des classes que nous pourrons créer (les classes à sémantique de valeur), et, depuis C++11, il est considéré comme abominable de ne pas avoir recours aux pointeurs intelligents, et aux fonctions std::make_shared et make_unique (même si cette dernière n'est arrivée qu'avec C++14).
    les
    Or, comme je te l'ai déjà dit, la version nothrow de new est encore une exception (je te l'ai déjà dit : on peut développer pendant des années sans en avoir besoin! ), ce qui en fait une exception à un cas qui devient lui-même de plus en plus exceptionnel. Tu te rends du coup bien compte que cette envie de l'utiliser "pour tout et n'importe quoi" devient particulièrement aberrante
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 140
    Points : 103
    Points
    103
    Par défaut
    Ok je comprends.
    Faut que je regarde justement ce qui se passe lors d'un lancement d'une exception et qu'elle n'est pas capturée : plantage de l'application d'une manière sale ou autre.
    Enfin, je vais supprimer de ma base de connaissances, mes réflexes, ce 'nothrow' plus qu'inutile, même à la mode 'grand-papa'. Car finalement cette utilisation se justifiait, lors de son apprentissage par le gourou de l'époque :-), par le fait que un programme qui plante sans savoir pourquoi, c'est sale ; et donc utiliser ce pattern permettait de remédier à cela.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par MicBeastKiller Voir le message
    Ok je comprends.
    Faut que je regarde justement ce qui se passe lors d'un lancement d'une exception et qu'elle n'est pas capturée : plantage de l'application d'une manière sale ou autre.
    Ben, un plantage, c'est toujours sale... Même quand on travaille avec des valeurs de retours!!!

    La seule différence entre une valeur d'erreur et une exception, c'est que l'exception remonte "automatiquement" (tant que l'on n'a pas de raison de l'arrêter), alors qu'un retour d'erreur doit être renvoyé de manière explicite quand il y a une erreur

    Mais, si tous les retours d'erreurs sont vérifiés et qu'il font remonter l'erreur (c'est souvent la seule solution dont on dispose en cas d'erreur), et qu'il veillent à faire correctement le ménage avant de partir, le principe de fonctionnement est sensisblement le même (on passe d'une fonction à celle qui l'a appelée, et ainsi de suite jusqu'à quitter même la fonction main() )

    Enfin, je vais supprimer de ma base de connaissances, mes réflexes, ce 'nothrow' plus qu'inutile, même à la mode 'grand-papa'. Car finalement cette utilisation se justifiait, lors de son apprentissage par le gourou de l'époque :-), par le fait que un programme qui plante sans savoir pourquoi,
    Généralement, quand un programme plante sur une exception, tu obtiens toujours un message t'indiquant l'exception qui est survenue...
    c'est sale ;
    Et un programme qui continue alors qu'il est dans un état incohérent (parce qu'on n'a pas fait attention au retour d'une fonction), c'est pas sale, c'est pas encore pire car potentiellement plus dangereux
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 140
    Points : 103
    Points
    103
    Par défaut
    Il est vrai.
    De ce fait il vaut mieux donc faire
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // ...
    Object * myObject( new Object );
    // Si l'allocation a échoué alors le programme ne vas pas plus loin et remonte l'exception (libre à moi de la capturer).
    // Si je continue ensuite avec 'myObject', je suis donc sûr qu'il existe bien et est bien alloué.
    myObject->DoSomething(); // Pas d'erreur ici (au moins pour l'appel de myObject)
    // ...
    DoSomethingWith( myObject ); // Pas d'erreur ici (au moins pour l'appel de myObject)
    // ...

Discussions similaires

  1. interaction sur des combo suite à un evenement
    Par stela86 dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 02/05/2006, 17h17
  2. [VB6] Vérification des droits de lecture/écriture sur répert
    Par marsup54 dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 01/02/2006, 18h41
  3. vérifications des dates
    Par smail21 dans le forum Bases de données
    Réponses: 5
    Dernier message: 05/11/2005, 16h02
  4. Avis sur la vérification des données d'une fiche
    Par AlexB59 dans le forum Composants VCL
    Réponses: 2
    Dernier message: 28/07/2005, 20h55

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