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

Qt Discussion :

Votre gestion d'erreur / exception avec Qt ? [Débat]


Sujet :

Qt

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Avatar de _skip
    Homme Profil pro
    Développeur d'applications
    Inscrit en
    Novembre 2005
    Messages
    2 898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur d'applications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 898
    Par défaut Votre gestion d'erreur / exception avec Qt ?
    Bonjour,

    Comme vous le savez sûrement, pour différentes raisons, Qt n'utilise pas les exceptions dans sa bibliothèque. Ceci me pose pas mal de problèmes, notamment lorsque j'utilise des QTextStream ou QDataStream par dessus des QFile (échec 100% silencieux).

    Mais même pour le reste, je serai intéressé de savoir quelles sont vos stratégies de gestion d'erreur, si vous avez tendance à utiliser des wrappers par dessus les objets QT qui eux lancent des exceptions ou si vous travaillez avec des valeurs de retour spécialisées...

    Je suis à la recherche de conseils en la matière...
    Merci d'avance

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 119
    Billets dans le blog
    148
    Par défaut
    Je suis plus pour des valeurs de retour spécialisée ( tendance à ne pas trop aimé les exceptions ( à tord ) ).

    Après pour le QDataStream, chez moi, quand il y avait echec, il était vide ... donc même si je lisais dedans, je n'avais pas de problème.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Membre éprouvé
    Avatar de _skip
    Homme Profil pro
    Développeur d'applications
    Inscrit en
    Novembre 2005
    Messages
    2 898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur d'applications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 898
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Je suis plus pour des valeurs de retour spécialisée ( tendance à ne pas trop aimé les exceptions ( à tord ) ).
    Sur certains points j'ai commencé à simplement lancer de bêtes QString comme exceptions. Pour simplifier car c'est un algo très court.

    Après pour le QDataStream, chez moi, quand il y avait echec, il était vide ... donc même si je lisais dedans, je n'avais pas de problème.
    C'est vrai mais là je suis sur un cas ou il est critique que je sache différencier le cas ou rien a été lu à cause d'une erreur ou si c'était simplement vide.

    Pour un cas embêtant d'une classe qui représente un consommateur dans une architecture multi-thread, j'en suis arrivé à ceci :

    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
     
    /**
     * Writes the content of a temporary file into the final result file.
     * The result file is assumed to be already open in write mode, after writing, content isn't flushed nor closed.
     *
     * @param tempFile A reference to a temporary file structure (or buffer), device will be opened in RO mode.
     * @param finalFile A reference to the final file, device needs to be already OPEN in Write mode.
     */
    void SyncResultWriter::mergeFile(QIODevice& tempFile, QFile& finalFile )
    {
        if( !tempFile.open( QIODevice::ReadOnly ) )
        {
            setError("Could not open temp file for merging!");
            return;
        }
     
        const int B_SIZE = 4096;
        char inBuffer[B_SIZE];
     
        //reads temp file block per block
        int bytesRead = tempFile.read(inBuffer, B_SIZE) ;
     
        while( bytesRead > 0 )
        {
            //write the current block to the definitive file
            if( finalFile.write( inBuffer, bytesRead ) == -1 )
            {
                setError( QString( "Error writing chunk : ") + finalFile.errorString() );
                return;
            }
     
            //next chunk
            bytesRead = tempFile.read(inBuffer, B_SIZE);
        }
     
        //if the loop was broken because of a reading error :
        if( bytesRead ==  -1 )
        {
            setError( QString( "Error reading chunk : ") + tempFile.errorString() );
            return;
        }
     
        //finalize line
        finalFile.write( "\n");
        tempFile.close();
    }
     
    /**
     * Informs if an error has occured somewhere during the writing process.
     * The result of this method can be tested after task completion.
     * @return True if an error occured, false otherwise.
     */
    bool SyncResultWriter::hasError()
    {
        return this->foundError;
    }
     
    /**
     * Returns the lastest error message. Use with hasError().
     * @return An error message String, or an empty String.
     */
    QString SyncResultWriter::errorString()
    {
        return this->errorMessage;
    }
     
    /**
     * Method used internally to set this object in error state.
     * @param message The error message to set. 
     */
    void SyncResultWriter::setError(QString message)
    {
        this->foundError = true;
        this->errorMessage = message;
    }
    Tester chaque lecture/écriture et mettre l'objet en status d'erreur.
    A la fin du processus, le thread principal teste ces valeurs et si jamais, il sait que le résultat de l'algo est à jeter.

    Mais c'est d'une lourdeur diabolique tous ces tests à chaque read/write.

  4. #4
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    En C++, y as pas de système d'exception thread safe.
    Qt implémente une solution pour les QtConcurrent. Tu peut peut être t'en inspirer.
    Rien ne t'empêche d'utiliser un système d'exeption dans le thread qui va mettre à jour setError.
    Ou qui par une fonction appelé par l'autre thread, re-emetter l' exception dans ce thread.

  5. #5
    Membre éprouvé
    Avatar de _skip
    Homme Profil pro
    Développeur d'applications
    Inscrit en
    Novembre 2005
    Messages
    2 898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur d'applications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 898
    Par défaut
    Non mais là j'ai un peu disgressé car la gestion d'exception inter threads est un problème dans tous les langages que je connais, on termine souvent avec des idées du style le thread qui déclenche une erreur (exception ou autre) la stocke et un autre thread la récupère le moment venu pour avertir d'utilisateur etc...

    Plus directement, je souhaitais parler de l'utilisation faite des objets QT. Actuellement je teste directement les valeurs de retour de chaque écriture / lecture. Je voulais juste savoir si certains d'entre vous avaient peut être tendance à encapsuler les objets QT pour en faire une sorte de mini framework qui lui lancerait des exceptions, ce genre de chose...

  6. #6
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    Les exceptions sont en général une fausse bonne idée. Elles conviennent à la gestion de cas... exceptionnels, pour lesquels le code appelant ne peut rien faire. Par exemple, tu lis un fichier, et hop il n'y a plus assez de mémoire pour continuer à bosser, que peux-tu faire ?

    En revanche, tester si l'ouverture d'un fichier a réussi est quelque chose qui fait parti du flot normal d'exécution d'un programme. Et c'est la responsabilité directe de l'appelant de faire ça. Un code de retour est alors mieux adapté.

    Tu trouves ton code pénible à écrire car s'il utilisait des exceptions tu pourrais faire plus concis... mais c'est une fausse impression. Quelque part dans ton logiciel il va te falloir générer les 3 messages que tu donnes à setError(). Et si tu ne le fais pas dans mergeFile(), tu vas devoir le faire ailleurs dans une fonction appelante. Alors oui le code de mergeFile() sera beaucoup + court, mais ton code appelant sera beaucoup + long :

    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
    try
    {
        mergefile(tmp, final);
    }
    catch ( const FileOpenError & e )
    {
        setError("Could not open temp file for merging!");
        return;
    }
    catch ( const FileReadError & e )
    {
        setError( QString( "Error reading chunk : ") + tempFile.errorString() );
        return;
    }
    catch ( const FileWriteError & e )
    {
        setError( QString( "Error writing chunk : ") + final.errorString() );
        return;
    }
    Tu ne peux pas échapper à ces lignes de code. Si tu ne les mets pas dans mergefile() tu devras les mettre ailleurs. Et je ne suis pas sûr que ce soit la meilleure des choses, car le exceptions ont ceci de particulier : elles exposent les détails d'implémentation et donc affaiblissent l'encapsulation.

    En ce qui me concerne, j'ai choisi une option hybride : j'utilise une classe comme valeur de retour, c.a.d qu'au lieu d'écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if( !tempFile.open( QIODevice::ReadOnly ) )
    {
        setError("Could not open temp file for merging!");
        return;
    }
    j'écris un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( !tempFile.open( QIODevice::ReadOnly ) )
    {
        return Error( tr( "Could not open temp file for merging!" ) );
    }
    ou bien un truc plus fun :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( !tempFile.open( QIODevice::ReadOnly ) )
    {
        return Error() << tr( "Could not open temp file for merging!" );
    }

    et le code appelant ne se soucie jamais du type de l'erreur. Il y a "une erreur" et c'est tout, y'a pas à se poser davantage de question. Il est du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Error err = mergefile();
    if ( err )
    {
        displayError( err );
    }
    Tu fais ce que tu veux de l'erreur récupérée : affichage, renvoie en code de retour, renvoie sous forme d'exception etc...

    En fait, j'ai exploré une autre voie, qui est celle-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( !tempFile.open( QIODevice::ReadOnly ) )
    {
        return Error::COULD_NOT_OPEN_FILE_FOR_MERGING;
    }
    dans le but de centraliser tous les messages d'erreur possibles, ce qui offre de nombreux avantages en ce qui concerne les messages affichés à l'utilisateur par une application.

    Mais ça ne convient pas très bien aux messages "internes" d'un composant réutilisable par exemple. Il faut ainsi distinguer plusieurs types d'erreurs dans son application, et traiter chaque type d'une manière spécifique clairement établie. Les exceptions conviennent - il me semble - aux erreurs les + sérieuses et les + rares, qui doivent être traitée à un niveau supérieur quand elles ne nécessitent pas de fermer le programme.

Discussions similaires

  1. Gestion des SEH Exceptions avec VC++ 2013
    Par Jimmy91 dans le forum C++
    Réponses: 4
    Dernier message: 11/08/2014, 10h08
  2. [PHP 5.3] Gestion des erreurs/exceptions pour GD (en POO)
    Par RunCodePhp dans le forum Langage
    Réponses: 1
    Dernier message: 07/03/2011, 16h09
  3. [Upload] Problème pour gestion d'erreur avec class
    Par allserv dans le forum Langage
    Réponses: 2
    Dernier message: 27/12/2005, 13h00
  4. [vb.net]Gestion des exceptions avec les web services
    Par mvr dans le forum Windows Forms
    Réponses: 2
    Dernier message: 05/12/2005, 22h41

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