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

C++ Discussion :

Exceptions et durées de vie


Sujet :

C++

  1. #1
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut Exceptions et durées de vie
    Suite à un petit problème que j'ai rencontré, j'aimerais avoir davantage d'infos sur le mécanisme des exceptions en C++ et la durée de vie de variables.

    Voici un exemple simple d'une exception:

    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
    class CMyException
    {
    public:
    	CMyException(const char * message) throw() : m_message(message) {}
    	~CMyException() throw() {}
     
    	const char * what() const throw() { return m_message; }
     
    protected:
    	const char * m_message;
    };
     
    void f()
    {
    	char message[] = { "FooBar" };
    	throw CMyException(message);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    try
    {
    	f();
    }
    catch (CMyException &e)
    {
    	cout << "Message: " << e.what() << endl;
    }
    La variable message sort de la portée lorsqu'on se trouve dans le catch, donc son contenu susceptible d'être écrasé.

    Voici la démonstration par le biais de la classe CMyString:

    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
    #include <iostream>
    #include <ServiceMgr/StringHlp.h>
     
    class CMyString
    {
    public:
    	CMyString(const char * buffer) : m_buffer(strdup(buffer))
    	{
    		std::cout << "Constructeur de CMyString" << std::endl;
     
    		m_buffer = new char[strlen(buffer) + 1];
    		strcpy(m_buffer, buffer);
    	}
     
    	~CMyString()
    	{
    		std::cout << "Destructeur de CMyString" << std::endl;
     
    		delete [] m_buffer;
    		m_buffer = 0;
    	}
     
    	const char * c_str() const { return m_buffer; }
     
    protected:
    	char * m_buffer;
    };
     
    void g()
    {
    	CMyString str("Toto");
     
    	throw CMyException(str.c_str());
    }
    Constructeur de CMyString
    Destructeur de CMyString
    Message: ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦└
    Donc, est-ce incorrect de passer une variable temporaire comme argument de mon exception?

  2. #2
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Déjà :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CMyString(const char * buffer) : m_buffer(strdup(buffer))
    	{
    		std::cout << "Constructeur de CMyString" << std::endl;
     
    		m_buffer = new char[strlen(buffer) + 1];
    		strcpy(m_buffer, buffer);
    	}
    Tu fuis de la mémoire à chaque exécution de ton constructeur (strdup n'a rien à faire ici vu que tu alloues derrière avec new, utilise plutôt m_buffer(NULL) pour initialiser à null).

    Ensuite, ton exception stocke un pointeur vers une chaîne de caractère, pas une chaîne de caractères elle-même. Donc, la libération de cet espace mémoire étant faite dans CMyString, le pointeur pointe vers de la mémoire libérée, bref, potentiellement n'importe quoi.

    Il faut que ton exception soit "self-contained", qu'elle ne référence rien d'extérieur qui est susceptible de disparaître avant elle. À noter que son constructeur n'a pas besoin d'être throw(), donc tu peux très bien utiliser un new dedans.

  3. #3
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Déjà :



    Tu fuis de la mémoire à chaque exécution de ton constructeur (strdup n'a rien à faire ici vu que tu alloues derrière avec new, utilise plutôt m_buffer(NULL) pour initialiser à null).
    Oups, un vestige que j'ai oublié de supprimer, bien sûr, il faut enlever strdup() et mettre NULL à la place.

    Citation Envoyé par white_tentacle Voir le message
    Ensuite, ton exception stocke un pointeur vers une chaîne de caractère, pas une chaîne de caractères elle-même. Donc, la libération de cet espace mémoire étant faite dans CMyString, le pointeur pointe vers de la mémoire libérée, bref, potentiellement n'importe quoi.
    C'est fait exprès, c'était pour illustrer le problème de l'exception.

    Citation Envoyé par white_tentacle Voir le message
    Il faut que ton exception soit "self-contained", qu'elle ne référence rien d'extérieur qui est susceptible de disparaître avant elle. À noter que son constructeur n'a pas besoin d'être throw(), donc tu peux très bien utiliser un new dedans.
    Ah je pensais qu'une exception ne devait en aucun cas pouvoir générer une exception , d'où la necessité de ne pas utiliser de std::string.

    Donc, comment tu écrirais la classe CMyException? Elle peut générer une exception?

  4. #4
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Elle ne doit pas lever d'exception dans son destructeur ni son constructeur de copie (potentiellement utilisé lors du catch, et c'est lui qui empêche l'usage de std::string), mais il me semble que dans un autre constructeur, tu as le droit.

    Cela dit, je reste toujours dubitatif face à l'argument comme quoi tu ne dois pas utiliser de types dont le constructeur de copie peut lancer une exception. Une exception s'attrape par référence, pas par copie. D'ailleurs, l'exemple sur les exceptions de la FAQ cpp de développez... utilise une std::string .

Discussions similaires

  1. Durée de vie d'une exception
    Par ram-0000 dans le forum Langage
    Réponses: 9
    Dernier message: 24/04/2009, 22h21
  2. [savoir] durée de vie d'un PC?
    Par afrikha dans le forum Composants
    Réponses: 20
    Dernier message: 24/10/2005, 13h28
  3. Réponses: 2
    Dernier message: 27/09/2005, 16h32
  4. [AS2] durée de vie d'une classe (extends movieclip)
    Par ooyeah dans le forum ActionScript 1 & ActionScript 2
    Réponses: 4
    Dernier message: 23/07/2005, 13h33
  5. prob de durée de vie de IDvdGraphBuilder
    Par Chaksss dans le forum DirectX
    Réponses: 11
    Dernier message: 30/12/2004, 16h09

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