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

Visual C++ Discussion :

[compilo Visual 2005] Fonctionnement du delete


Sujet :

Visual C++

  1. #1
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 142
    Points : 185
    Points
    185
    Par défaut [compilo Visual 2005] Fonctionnement du delete
    Bonjour à tous,

    J'ai une question sur le fonctionnement de l'opérateur delete en debug avec le compilo de Visual 2005.
    Pour vous donner le contexte, nous devons réaliser un container de type anneau.
    Nous avons tout d'abord une structure de type liste chainée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct tNode
    {
     T* elt;
     tNode* next_elt;
    }
    Nous avons ensuite une classe dans laquelle nous allouons au constructeur un tableau de tNode:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tNode* nodes = new tNode[size_max+1];
    Et enfin dans le destructeur de la classe, nous devons désallouer bien sur. Mais nous ne pouvons utiliser l'opérateur delete[] car certains éléments pourraient encore être utilisés ailleurs.
    Nous faisons donc une boucle sur les éléments à libérer, mais voilà le delete semble libérer tout le tableau.

    Concrètement, voici ce que nous avons en mémoire après allocation:
    0x003663CC fd fd fd fd ýýýý
    0x003663D0 00 00 00 00 ....
    0x003663D4 d8 63 36 00 Øc6.
    0x003663D8 00 00 00 00 ....
    0x003663DC e0 63 36 00 àc6.
    0x003663E0 00 00 00 00 ....
    0x003663E4 e8 63 36 00 èc6.
    0x003663E8 00 00 00 00 ....
    0x003663EC d0 63 36 00 Ðc6.
    0x003663F0 fd fd fd fd ýýýý
    Le tableau commence à 0x003663D0 et se finit à 0x003663EC, pas de problème.
    Nous déclarons un pointeur sur le 1er élement du tableau, puis nous faisons un delete sur ce pointeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    tNode* elt = nodes[0];
    delete elt;
    où front est un attribut de la classe qui pointe vers le 1er élément du tableau.
    Et voila ce que nous avons en mémoire après ces instructions :
    0x003663CC ee fe ee fe îþîþ
    0x003663D0 ee fe ee fe îþîþ
    0x003663D4 ee fe ee fe îþîþ
    0x003663D8 ee fe ee fe îþîþ
    0x003663DC ee fe ee fe îþîþ
    0x003663E0 ee fe ee fe îþîþ
    0x003663E4 ee fe ee fe îþîþ
    0x003663E8 ee fe ee fe îþîþ
    0x003663EC ee fe ee fe îþîþ
    0x003663F0 ee fe ee fe îþîþ
    Apparemment le tableau a été libéré dans son intégralité !! Comme si nous avions fait un delete[], ce que nous voulions justement éviter.
    J'aimerais donc savoir si c'est bien le compilo Visual qui ne respecte pas la norme, et qui désalloue jusqu'à rencontrer fd fd fd fd, alors qu'il ne devrait désallouer que l'élément pointé par elt ?

    Merci par avance pour votre aide.

  2. #2
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Bonjour,

    C'est un comportement normal. Le problème vient du fait que tu alloues une tableau de tNode:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    tNode* nodes = new tNode[size_max+1];
    Alors que c'est plus probablement un tableau de pointeur de tNode que tu souhaitais (comme ça tu peux libérer n'importe quel objet du tableau sans libérer le tableau entier). Du coup, à la libération, c'est tout le tableau qui disparait.

    Code minimal du problème:

    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
     
    typedef struct _TNODE{
     
    	int elem;
    	struct _TNODE* next;
     
    }TNODE, *PTNODE;
     
    #define MAX_SIZE 10
    int main(int argc, char* argv[])
    {	
    	PTNODE nodes = new TNODE[MAX_SIZE];
     
    	for(int i = 0; i < MAX_SIZE; i++)
    	{
    		nodes[i].elem = i;
    		if(i < MAX_SIZE - 1)
    			nodes[i].next = &nodes[i+1];
    		else
    			nodes[i].next = &nodes[0];
    	}
     
    	delete nodes; //libère tout le tableau!
     
    	return 0;
    }
    Ce que tu souhaites faire, c'est probablement quelque chose comme ça (code minimal avec un tableau, à débugger):
    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
     
    typedef struct _TNODE{
     
    	int elem;
    	struct _TNODE* next;
     
    }TNODE, *PTNODE;
     
    #define MAX_SIZE 10
    int main(int argc, char* argv[])
    {	
    	//tableau de pointeur vers TNODE*
    	PTNODE* nodes = new PTNODE[MAX_SIZE];
     
    	//init elem
    	for(int i = 0; i < MAX_SIZE; i++)
    	{
    		PTNODE pnode = new TNODE;
    		pnode->elem = i;
     
    		nodes[i] = pnode;
    	}
     
    	//init next
    	for(int i = 0; i < MAX_SIZE; i++)
    	{
    		if( i < (MAX_SIZE - 1))
    			nodes[i]->next = nodes[i+1];
    		else
    			nodes[i]->next = nodes[0];
    	}
     
    	//efface 'node' à index 1
    	delete nodes[1];
    #ifndef _DEBUG
    	nodes[1] = NULL;
    #endif
     
    	//node[0]->next pointe maintenant vers node[2]
    	nodes[0]->next = nodes[2];
     
    	//affichage
    	PTNODE current_node = nodes[0];
    	do
    	{
    		printf("[%p] elem: %d ; next: %p\n", current_node, current_node->elem, current_node->next);
    		current_node = current_node->next;
    	}while(current_node != nodes[0]);
     
    	//test sur élément libéré.
    #ifdef _DEBUG
    	printf("[%p] elem: %d ; next: %p\n", nodes[1], nodes[1]->elem, nodes[1]->next);
    #endif
     
    	//libération des pointeurs
    	current_node = nodes[0];
    	do
    	{
    		PTNODE next = current_node->next;
    		delete current_node;
    		current_node = next;
    	}while(current_node != nodes[0]);
     
    	//libère tableau
    	delete[] nodes; 
     
    	return 0;
    }
    Ceci dit, pour une liste circulaire, tu peux très bien te passer du tableau (je dirais même que c'est plutôt recommandé).

    Chaque élément pointe vers le suivant ('next'). La disparition (libération) d'un noeud doit alors obligatoirement s'accompagner d'une mise à jour du pointeur 'next' de l'élément qui pointait sur celui libéré: comme ça, plus besoin de tableau !

  3. #3
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 142
    Points : 185
    Points
    185
    Par défaut
    Merci beaucoup pour ta réponse. J'avais complétement oublié de revenir après l'avoir lu et fait qq tests, désolé.

    En fait j'avais bien besoin d'un tableau de tNode et non de tNode*, ceci dans un but de performance, et donc pour éviter de faire appel un trop grand nombre de fois à new().
    Mais j'ai contourné le problème d'une autre manière.

    Ceci dit, il y a quand même qqch qui m'échappe, tu dis "C'est un comportement normal".

    Hors il me semblait que quand on allouait un tableau d'objets quelconques, avec Obj* tab = new Obj[n], alors il fallait le libérer avec delete[], qu'un simple delete ne libérait que le 1er élément, ou que le comportement était indéfini (j'ai lu les 2 possibilités sur le net).
    Hors ici, il semble que le delete sans les [] libère bien tout le tableau, voila pourquoi je pensais que le compilo de visual prenait des libertés avec la norme.
    Cela reste assez mystérieux pour moi.

    Encore merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Migration] Comment réussir VC6.0 >> Visual 2005
    Par ep31 dans le forum EDI/Outils
    Réponses: 6
    Dernier message: 06/07/2006, 17h21
  2. Visual 2005 & Qt4 Opensource
    Par chkpos dans le forum MFC
    Réponses: 3
    Dernier message: 08/02/2006, 18h08
  3. OpenMP sous Visual 2005
    Par teddy fredaigues dans le forum MFC
    Réponses: 6
    Dernier message: 19/01/2006, 14h43
  4. [Visual 2005] Dacris et NETXP sous visual 2005
    Par Dinytro dans le forum Windows Forms
    Réponses: 5
    Dernier message: 06/09/2005, 12h30

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