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

Macros et VBA Excel Discussion :

à propos de la fonction Class_Terminate


Sujet :

Macros et VBA Excel

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    1 271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 1 271
    Points : 882
    Points
    882
    Par défaut à propos de la fonction Class_Terminate
    Bonjour, lorsque l'on crée un module de classe, il faut toujours créer les fonctions Class_Initialize (que j'assimile à un constructeur par défaut) et Class_Terminate (que j'assimile au destructeur de la classe). J'ai fait pas mal de C++ donc j'utilise ce vocabulaire.

    Dans des tutoriels, je lis très souvent qu'après chaque "new" il faut faire un libérer la mémoire (en gros set mon_truc = nothing).

    J'ai une classe qui contient pas mal de dictionnaires, de "new" vers d'autres classes etc..., du coup mon destructeur ressemble à 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
    76
    77
    78
     
    'destructeur
    Private Sub Class_Terminate()
     
    Dim usine As Variant
    Dim pvt As Variant
    Dim cad As Variant
    Dim nomMoule As Variant
    Dim cai As Variant
    Dim indicePP04 As Variant
     
    Set wb_ = Nothing
    Set ws_ = Nothing
     
    'destruction de l'attribut planProd_
    For Each usine In planProd_.keys
        For Each pvt In planProd_(usine).keys
            For Each cad In planProd_(usine)(pvt).keys
                Set planProd_(usine)(pvt)(cad) = Nothing
            Next cad
            Set planProd_(usine)(pvt) = Nothing
        Next pvt
        Set planProd_(usine) = Nothing
    Next usine
    Set planProd_ = Nothing
     
    'destruction de l'attribut tonnageAvantPIPO_
    For Each usine In tonnageAvantPIPO_.keys
        Set tonnageAvantPIPO_(usine) = Nothing
    Next usine
    Set tonnageAvantPIPO_ = Nothing
     
    'destruction de l'attribut dicoNbMoules_
    For Each usine In dicoNbMoules_.keys
        Set dicoNbMoules_(usine) = Nothing
    Next usine
    Set dicoNbMoules_ = Nothing
     
    'destruction de l'attribut dicoComplementNbMoules_
    For Each usine In dicoComplementNbMoules_.keys
        For Each nomMoule In dicoComplementNbMoules_(usine).keys
            Set dicoComplementNbMoules_(usine)(nomMoule) = Nothing
        Next nomMoule
        Set dicoComplementNbMoules_(usine) = Nothing
    Next usine
    Set dicoComplementNbMoules_ = Nothing
     
    'destruction de l'attribut dicoChargeMoules_
    For Each usine In dicoChargeMoules_.keys
        For Each nomMoule In dicoChargeMoules_(usine).keys
            Set dicoChargeMoules_(usine)(nomMoule) = Nothing
        Next nomMoule
        Set dicoChargeMoules_(usine) = Nothing
    Next usine
    Set dicoChargeMoules_ = Nothing
     
    'destruction de l'attribut dicoComplementCapaMoule_
    For Each usine In dicoComplementCapaMoule_.keys
        For Each cai In dicoComplementCapaMoule_(usine)
            Set dicoComplementCapaMoule_(usine)(cai) = Nothing
        Next cai
        Set dicoComplementCapaMoule_(usine) = Nothing
    Next usine
    Set dicoComplementCapaMoule_ = Nothing
     
    'destruction de l'attribut planProdIndicePP04_
    For Each usine In planProdIndicePP04_.keys
        For Each cad In planProdIndicePP04_(usine).keys
            For Each indicePP04 In planProdIndicePP04_(usine)(cad).keys
                Set planProdIndicePP04_(usine)(cad)(indicePP04) = Nothing
            Next indicePP04
            Set planProdIndicePP04_(usine)(cad) = Nothing
        Next cad
        Set planProdIndicePP04_(usine) = Nothing
    Next usine
    Set planProdIndicePP04_ = Nothing
     
    End Sub
    Si je mets tout ce code en commentaire, je m'aperçois que les autres fonctions Class_Terminate sont quand même appelées. A quoi bon se "fatiguer" à coder un tel destructeur ? De plus, puis-je le raccourcir de la manière suivante :
    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
     
    'destructeur
    Private Sub Class_Terminate()
     
    Set wb_ = Nothing
    Set ws_ = Nothing
     
    'destruction de l'attribut planProd_
    Set planProd_ = Nothing
     
    'destruction de l'attribut tonnageAvantPIPO_
    Set tonnageAvantPIPO_ = Nothing
     
    'destruction de l'attribut dicoNbMoules_
    Set dicoNbMoules_ = Nothing
     
    'destruction de l'attribut dicoComplementNbMoules_
    Set dicoComplementNbMoules_ = Nothing
     
    'destruction de l'attribut dicoChargeMoules_
    Set dicoChargeMoules_ = Nothing
     
    'destruction de l'attribut dicoComplementCapaMoule_
    Set dicoComplementCapaMoule_ = Nothing
     
    'destruction de l'attribut planProdIndicePP04_
    Set planProdIndicePP04_ = Nothing
     
    End Sub
    Y a-t-il un risque que la mémoire ne soit pas totalement libérée (donc qu'un "pointeur" ne soit pas remis à nothing (ou NULL en C++)) ?

    Merci bcp

    Bonne journée

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    février 2010
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2010
    Messages : 140
    Points : 270
    Points
    270
    Par défaut
    Bonjour,

    Cette question s'adresse à des gens déjà d'un certain niveau que je n'ai pas et tu en sais déjà probablement plus que moi sur le sujet.
    Mais j'ai effectivement l'habitude de vider les class en utilisant ta première méthode plus longue. Je dois dire que je n'est jamais eu de class charger avec de grande quantité d'objet. Du coup cela me vas bien. Ceci étant j'ai déjà lu quelque par sur un site en anglais que de passer la class elle même à nothing la vide de tout son contenu en gros on la tue.
    Voir même si ta class est créée dans une procédure le fait de terminer cette procédure cela videra la class automatiquement.

    Voila tout ce que je sais ! dans l’espoir que cela t'aide un petit peu

    A+

    ps : tu peux aller voir ici ou la

  3. #3
    Expert éminent
    Homme Profil pro
    Inscrit en
    août 2010
    Messages
    3 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : août 2010
    Messages : 3 453
    Points : 6 856
    Points
    6 856
    Par défaut
    Bonjour,

    Initialize et Terminate sont des procédures événementielles de la classe et ne servent ni à créer ni à détruire la classe (Initialize est appelée juste avant la création de la classe et Terminate est appelée juste avant la destruction de la classe) mais par exemple à faire des actions ou initialiser des variables dont la classe aurait éventuellement besoin !

  4. #4
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    juin 2019
    Messages
    285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : juin 2019
    Messages : 285
    Points : 461
    Points
    461
    Par défaut
    Bonjour,
    les module de classe ont tous implicitement un constructeur New et un destructeur ~.

    la méthode New est inaccessible en vba on ne peut donc pas y implémenter du code, on utilise donc la méthode New implicite!

    Class_Initialize permet d’initialiser certaine variables qui appartienne à la classe ou pas et Class_Terminate permet de redéfinir des variable externe à la classe ou libérer des objets de la mémoire!


    Code Classe1 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Private dico As Object
    Private Sub Class_Initialize()
     Set dico = CreateObject("Scripting.Dictionary")
    End Sub
    Private Sub Class_Terminate()
     Set dico = Nothing
    End Sub
    Public Sub Add(Name As String)
    If Not dico.exists(Name) Then dico.Add Name, New classe2
    End Sub

    dans l'exemple ci dessus, on trouve une variable privé du type Dictionary!
    Class_Initialize instancie un Nouveau Dictionary
    Sub Add(Name As String) ajoute un item à Dico ainsi qu'une instance de classe2!
    Class_Terminate place dico à nothing

    notes que dico.Add Name, New classe2 fait appel à Class_Initialize de la classe2 et que Set dico = Nothing appel en cascade la méthode Class_Terminate des classe2


    si tu as géré la méthode Class_Terminate dans tous tes module de classe, tu n'as besoin que de ça!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Private Sub Class_Terminate()
    Set planProd_ = Nothing
    End Sub
    dans ton code du post #1 tu fais un For Each!

    tu raisonne en procédural pas en programmation objet!

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    1 271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 1 271
    Points : 882
    Points
    882
    Par défaut
    Bonsoir

    merci Thumb down, c'est plus clair. Effectivement ,c'est bien ce que j'avais remarqué que les "for each" ne servent pas à grand chose car tous mes destructeurs sont appelés récursivement. Je pensais juste remettre les pointeurs à NULL (désolé de mon vocabulaire C++) avec tous les set machin = nothing.

    Theze : Avec ta réponse, je comprends mieux la différence entre un destructeur "à la C++" et une procédure événementielle. Si je comprends bien, il n'y a même pas besoin de faire les set machin = nothing car la classe est détruite toute seule ? J'avais lu qu'après chaque new il fallait faire un set nothing (d'où tous mes for each à n'en plus finir)

  6. #6
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    juin 2019
    Messages
    285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : juin 2019
    Messages : 285
    Points : 461
    Points
    461
    Par défaut
    Bonjour,
    En fait il faut liber les objets comme dans mon exemple le dico!
    Dico->0 set dico=Nothing en c++ on fait pointer dico sur 0 en VBA on le référence à Nothing, je ne me souviens plus de l'instruction mais C++ peut fonctionner par pointeur ou par référence !

    Mais tous ça c'est vieux ! Faire du C++ sur unix et VI ça inspire le respect.

    Vue que classe2 est dans la portée de dico on voit les méthodes terminate s'exécuter en cascade!

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    1 271
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 1 271
    Points : 882
    Points
    882
    Par défaut
    Re,
    en C++ on utilise delete ou delete []
    en C on utilise free

    mais dans l'exemple ci-dessous

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    set monDico = createObjet("Scripting.Dictionnary")
    monDico.add "toto", new MaClasse
    monDico.add "tata", new MaClasse
    si on fait un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    set monDico = nothing
    alors ok monDico vaut NULL (vocabulaire C++) suite à la libération de la mémoire, mais les 2 pointeurs créés avec le new ne sont pas remis à NULL (bien sur le class_terminate de MaClasse libère lui aussi les objets.

    Mais bon, il ne faut pas que ça me fasse un point de côté. Avec tes commentairs, j'ai pas mal diminué la longueur de mes class_terminate

    merci bcp

  8. #8
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    juin 2019
    Messages
    285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : juin 2019
    Messages : 285
    Points : 461
    Points
    461
    Par défaut
    Bonjour,
    Si je devais résumer , je dirais que la durée de vie d'une variable ou d'un objet dépend de sa portée. Et la portée des MaClasse dépend de la durée de vie de monDico!

  9. #9
    Rédacteur/Modérateur

    Avatar de Jean-Philippe André
    Homme Profil pro
    Developpeur VBA, C# et VB.Net =]
    Inscrit en
    juillet 2007
    Messages
    13 688
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Canada

    Informations professionnelles :
    Activité : Developpeur VBA, C# et VB.Net =]
    Secteur : Finance

    Informations forums :
    Inscription : juillet 2007
    Messages : 13 688
    Points : 31 224
    Points
    31 224
    Cycle de vie d'un bon programme :
    1/ ca fonctionne 2/ ca s'optimise 3/ ca se refactorise

    Pas de question technique par MP, je ne réponds pas

    Apprendre à programmer avec Access 2016 et Access 2019

    Pensez à consulter la FAQ Excel et la FAQ Access

    Derniers tutos
    Excel et les paramètres régionaux
    Les fichiers Excel binaires : xlsb,

    Autres tutos

  10. #10
    Responsable Access

    Avatar de Arkham46
    Profil pro
    Inscrit en
    septembre 2003
    Messages
    5 720
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : septembre 2003
    Messages : 5 720
    Points : 12 967
    Points
    12 967
    Par défaut
    Bonjour,

    Il est indispensable de mettre explicitement un objet à Nothing en cas de référence circulaire.
    Sinon ce n'est pas souvent utile.

Discussions similaires

  1. Question à propos d'une fonction
    Par 0ColdZero0 dans le forum C++
    Réponses: 4
    Dernier message: 22/04/2009, 01h47
  2. Fonction Class_Terminate non appelée sur set nothing
    Par zesamoth dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 04/06/2008, 13h00
  3. A propos de la fonction AlphaBetaWithMemory
    Par tsing dans le forum Intelligence artificielle
    Réponses: 4
    Dernier message: 15/04/2008, 16h05
  4. [FTP] Question à propos de la fonction copy()
    Par Mo_Poly dans le forum Langage
    Réponses: 2
    Dernier message: 10/04/2008, 12h36
  5. [VB][INFO] A propos de la fonction Round
    Par L.nico dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 10/03/2005, 12h59

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