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 :

libération de toute la mémoire allouée


Sujet :

C

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

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 299
    Par défaut libération de toute la mémoire allouée
    Bonjour, cela fait de très nombreuses fois que je lis que lorsqu'il y a une erreur irrécupérable, il faut

    1) faire remonter l'erreur au main()
    2) libérer toute la mémoire allouée
    3) quitter le main.

    Ma question est : existe-t-il une manière propre pour libérer toute la mémoire et ce, à n'importe quel moment (enfin dès qu'il y a une erreur) ?

    J'envisage de faire une structure du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    typedef struct
    {
      field1 * f1;
       ...
      field50 * f50;
    } Memory;
    et dès que je crée une structure dans mon main, je immédiatement après

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Memory -> f48 = f48; /* copie de pointeur */
    puis dès qu'il y a une erreur, faire "tout simplement" un DestroyMemory().

    Est-ce une bonne idée de fonctionner ainsi ?

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Non, en C il n'y a rien pour cela.
    Mais généralement, en cas d'erreur fatale irrécupérable, on ne se préoccupe pas de ça: On termine le processus, et l'OS détruit tout ce qui appartient au processus...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 299
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Non, en C il n'y a rien pour cela.
    Mais généralement, en cas d'erreur fatale irrécupérable, on ne se préoccupe pas de ça: On termine le processus, et l'OS détruit tout ce qui appartient au processus...
    salut, oui c'est ce que je fais en ce moment : j'utilise la fonction exit() à tout va : erreur dans un fopen(), dan un malloc() etc... et je laisse l'OS détruire tout ce qu'il doit détruire...

    mais j'ai lu de nombreuses fois que ce n'était pas bien de faire ainsi, d'où mon post...

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Je pense que ce qu'on te reproche, c'est plutôt de considérer un peu vite cela comme une erreur irrécupérable...

    Sinon:
    Normalement, tous les chemins d'une fonction doivent libérér la mémoire temporaire allouée dans la fonction. Il ne devrait donc pas y avoir de problème lors de la "remontée jusqu'au main()"...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 299
    Par défaut
    oui, effectivement, pour moi toute erreur est irrécupérable

    sinon, voici en gros mon code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int main(void)
    {
      ici j'alloue toute les structures dont j'ai besoin
      ici je calcule tout ce dont j'ai besoin avec tout plein de fct. Bien entendu, s'il y a un malloc dans une des fonctions, il y a un free aussi.
     
      ici je libère la mémoire (toutes les structures allouée plus haut (1e étape))
     
      return 0;
    si maintenant, dans une fct il y a un malloc qui échoue (par exemple), je fais exit() sans arriver à la partie libération de la mémoire...

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Ben oui, faire mieux n'est pas aisé.
    Il faudrait que toutes tes fonctions puissent retourner un code d'erreur, et que chaque fonction, en cas d'erreur, libère ce qu'elle a alloué avant de retourner au niveau supérieur...

    Sinon, tu peux regarder ma dernière c****rie en C et C++, qui permet de libérer la mémoire en cas de return. Je pensais l'étendre à un modèle d'exceptions à base de setjmp()/longjmp(), mais je n'ai pas eu le temps.
    En fait, il ne devrait pas être si difficile d'ajouter un mécanisme de sortie rapide, qui libérerait tout avant d'appeler exit(). Ce serait en tout cas moins complexe qu'un système d'exceptions...
    Code C : 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
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    /*
    Destructors.h
    */
    #pragma once
    #ifndef EXTERN_C
    	#ifdef __cplusplus
    		#define EXTERN_C extern "C"
    	#else
    		#define EXTERN_C extern
    	#endif
    #endif
    #include "MyStack.h"
     
    //----------------------------------------------------------------------------
    //Macros
     
    //Frame structure name
    #if 0
    	#define FRAME_STRUCT_NAME_BEGIN FrameStruct42 ## __LINE__ //Doesn't work: appears as "FrameStruct42__LINE__"
    	#define FRAME_STRUCT_PTR_END    NULL
    #else
    	#define FRAME_STRUCT_NAME_BEGIN FrameStruct42
    	#define FRAME_STRUCT_PTR_END    &FrameStruct42
    #endif
     
    //Debug macro to be used with the frame structure name
    #if 0
    	#define INITIALIZE_FRAME2(name) InitializeFrameDebug(&name, #name)
    #else
    	#define INITIALIZE_FRAME2(name) InitializeFrame(&name)
    #endif
    #define INITIALIZE_FRAME(name) INITIALIZE_FRAME2(name)
     
    //Base structure contents (with additional field(s) in Debug mode)
    #ifdef _DEBUG
    	#define BASE_FRAME          {NULL, NULL, FALSE, FALSE, FALSE, 0}
    	#define BASE_FUNCTION_FRAME {NULL, NULL, TRUE,  FALSE, FALSE, 0}
    	#define BASE_SWITCH_FRAME   {NULL, NULL, FALSE, TRUE,  FALSE, 0}
    	#define BASE_LOOP_FRAME     {NULL, NULL, FALSE, TRUE,  TRUE,  0}
    #else
    	#define BASE_FRAME          {NULL, NULL, FALSE, FALSE, FALSE}
    	#define BASE_FUNCTION_FRAME {NULL, NULL, TRUE,  FALSE, FALSE}
    	#define BASE_SWITCH_FRAME   {NULL, NULL, FALSE, TRUE,  FALSE}
    	#define BASE_LOOP_FRAME     {NULL, NULL, FALSE, TRUE,  TRUE }
    #endif
     
    //Macros to be used in the source code
    #ifdef __cplusplus
    	#define BEGIN_FUNCTION { CppFrame FRAME_STRUCT_NAME_BEGIN(TRUE,  FALSE, FALSE);
    	#define SWITCH(expr)   { CppFrame FRAME_STRUCT_NAME_BEGIN(FALSE, TRUE,  FALSE); switch(expr){
    	#define BEGIN_LOOP     { CppFrame FRAME_STRUCT_NAME_BEGIN(FALSE, TRUE,  TRUE );
    	#define BEGIN          { CppFrame FRAME_STRUCT_NAME_BEGIN(FALSE, FALSE, FALSE);
     
    	#define END_FUNCTION }
    	#define END_SWITCH   }}
    	#define END_LOOP     }
    	#define END          }
     
    	#define RETURN return;
    	#define BREAK  break;
    #else
    	#define BEGIN_FUNCTION { struct frame FRAME_STRUCT_NAME_BEGIN = BASE_FUNCTION_FRAME; INITIALIZE_FRAME(FRAME_STRUCT_NAME_BEGIN); {
    	#define SWITCH(expr)   { struct frame FRAME_STRUCT_NAME_BEGIN = BASE_SWITCH_FRAME;   INITIALIZE_FRAME(FRAME_STRUCT_NAME_BEGIN); switch(expr){
    	#define BEGIN_LOOP     { struct frame FRAME_STRUCT_NAME_BEGIN = BASE_LOOP_FRAME;     INITIALIZE_FRAME(FRAME_STRUCT_NAME_BEGIN); {
    	#define BEGIN          { struct frame FRAME_STRUCT_NAME_BEGIN = BASE_FRAME;          INITIALIZE_FRAME(FRAME_STRUCT_NAME_BEGIN); {
     
    	#define END_FUNCTION } assert(IsTopFrameReturnLimit(FRAME_STRUCT_PTR_END)); UninitializeFrameNormal(FRAME_STRUCT_PTR_END); }
    	#define END_SWITCH   } assert(IsTopFrameBreakLimit( FRAME_STRUCT_PTR_END)); UninitializeFrameNormal(FRAME_STRUCT_PTR_END); }
    	#define END_LOOP     } assert(IsTopFrameBreakLimit( FRAME_STRUCT_PTR_END)); UninitializeFrameNormal(FRAME_STRUCT_PTR_END); }
    	#define END          }                                                      UninitializeFrameNormal(FRAME_STRUCT_PTR_END); }
     
    	#define RETURN { UninitializeFrameReturn(FRAME_STRUCT_PTR_END); return; }
    	#define BREAK  { UninitializeFrameBreak(FRAME_STRUCT_PTR_END);  break; }
    #endif
     
    //----------------------------------------------------------------------------
    //Data structures
     
    struct frame
    {
    	struct frame * pParentFrame;
    	struct st_stackOfDestructors *pDestructors;
    	BOOL bReturnLimit;
    	BOOL bBreakLimit;
    	//TRUE for loops because object is inside the loop,
    	//FALSE for switches because object is out of the switch
    	BOOL bPopOnBreak;
    	#ifdef _DEBUG
    	int cnt;
    	#endif
    #ifdef __cplusplus
    protected:
    	frame(void)
    	 : pParentFrame(NULL), pDestructors(NULL)
    	{ }
    #endif
    };
     
    //----------------------------------------------------------------------------
    //Functions
     
    EXTERN_C void InitializeFrame(struct frame *pFrame);
    EXTERN_C void InitializeFrameDebug(struct frame *pFrame, char const *name);
    EXTERN_C void UninitializeFrameNormal(struct frame *pFrame);
    EXTERN_C void UninitializeFrameBreak(struct frame *pFrame);
    EXTERN_C void UninitializeFrameReturn(struct frame *pFrame);
    EXTERN_C BOOL IsTopFrameBreakLimit(struct frame *pFrame);
    EXTERN_C BOOL IsTopFrameReturnLimit(struct frame *pFrame);
    EXTERN_C void AddDestructor(void *pObj, DESTROYPROC proc);
    EXTERN_C void FrameDebugIndent(void);
     
    #ifdef __cplusplus
    class CppFrame : private frame
    {
    public:
    	explicit CppFrame(BOOL bReturnLimit, BOOL bBreakLimit, BOOL bPopOnBreak)
    	{
    		this->bReturnLimit = bReturnLimit;
    		this->bBreakLimit = bBreakLimit;
    		this->bPopOnBreak = bPopOnBreak;
    		InitializeFrame(this);
    	}
    	CppFrame(frame const &src)
    	: frame(src)
    	{
    		InitializeFrame(this);
    	}
    	~CppFrame(void)
    	{
    		UninitializeFrameNormal(this); //In C++, it's always 'normal'.
    	}
    };
    #endif
    Code C : 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
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    /*
    Destructors.c
    */
    #include "stdafx.h"
    #include "Destructors.h"
     
    struct st_stackOfDestructors;
    struct frame;
    void FrameDebugIndent(void);
     
    //
    //============================================================================
    //TLS-related functions and data
     
    //Thread-local data structure.
    struct threadFrameMemory
    {
    	struct frame * pCurrentTopFrame;
    };
     
    //TLS index for the data structure
    static volatile DWORD g_tlsIndexFrames = TLS_OUT_OF_INDEXES;
    //FALSE until the first call to GetThisThreadFrameMemory()
    static volatile LONG g_bInitializationAlreadyStarted = FALSE;
     
    /*
    Abort!
    ------ */
    static void MyAbort(char const *msg)
    {
    	//Test console process
    	BOOL bConsole = FALSE;
    	SetLastError(ERROR_SUCCESS);	
    	{
    		HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    		DWORD type = GetFileType(hOut);
    		DWORD err = GetLastError();
    		if(err == ERROR_SUCCESS)
    			bConsole = TRUE;
    		(void)type;
    	}
    	//Display the message on console or message box.
    	if(msg==NULL)
    		msg = "(no message)";
    	if(bConsole)
    	{
    		printf("-------------------------------------------------------------------------------\n--- Destructors Error: ");
    		puts(msg);
    		puts("Press [Enter] to quit");
    		{
    			int c;
    			while((c=getchar())!='\n' && c!=EOF);
    		}
    	}
    	else
    	{
    		MessageBoxA(NULL, msg, "Destructors Error", MB_OK | MB_ICONERROR);
    	}
    	abort();
    }
     
    /*
    Get a pointer the thread-local data structure (initializing if necessary)
    ------------------------------------------------------------------------- */
    static struct threadFrameMemory * GetThisThreadFrameMemory(void)
    {
    	struct threadFrameMemory * pMem = NULL;
     
    	//Alloc TLS if necessary
    	if(g_tlsIndexFrames == TLS_OUT_OF_INDEXES)
    	{
    		//If not already initializing, do it.
    		//Else, wait until initialized
    		if(InterlockedCompareExchange(&g_bInitializationAlreadyStarted, TRUE, FALSE) == FALSE)
    		{
    			g_tlsIndexFrames = TlsAlloc();
    		}
    		else
    		{
    			while(g_tlsIndexFrames==TLS_OUT_OF_INDEXES) {}
    		}
    	}
    	//If TLS is failed, abort!
    	if(g_tlsIndexFrames == TLS_OUT_OF_INDEXES)
    		MyAbort("TLS slot allocation failed.");
     
    	//Get the memory pointer, allocating if necessary
    	pMem = TlsGetValue(g_tlsIndexFrames);
    	if(pMem == NULL)
    	{
    		static const struct threadFrameMemory strInit = {0};
    		pMem = malloc(sizeof *pMem);
    		if(pMem != NULL)
    		{
    			*pMem = strInit;
    			TlsSetValue(g_tlsIndexFrames, pMem);
    		}
    	}
    	//If failed, abort!
    	if(pMem == NULL)
    		MyAbort("TLS data structure mem alloc failed.");
     
    	return pMem;
    }
     
    //
    //============================================================================
    //Frame-stack-related functions and data
     
    /*
    Get the frame pointer slot from the Thread-local data structure
    --------------------------------------------------------------- */
    static struct frame ** GetFramePointerSlotForThisThread(void)
    {
    	struct threadFrameMemory * pMem = GetThisThreadFrameMemory();
    	assert(pMem!=NULL);
     
    	return &(pMem->pCurrentTopFrame);
    }
     
    /*
    Get the top of the frame stack (the deepest frame)
    -------------------------------------------------- */
    static struct frame * TopFrame(void)
    {
    	struct frame ** const ppThreadFrame = GetFramePointerSlotForThisThread();
    	return *ppThreadFrame;
    }
     
    /*
    Push an initialized frame to the frame stack
    -------------------------------------------- */
    static void PushFrame(struct frame *pFrame)
    {
    	assert(pFrame!=NULL);
    	assert(pFrame->pParentFrame==NULL);
     
    	{
    		struct frame ** const ppThreadFrame = GetFramePointerSlotForThisThread();
    		struct frame * const pParentFrame = *ppThreadFrame;
    		#ifdef _DEBUG
    		if(pParentFrame!=NULL)
    			pFrame->cnt = pParentFrame->cnt + 1;
    		else
    			pFrame->cnt = 1;
    		FrameDebugIndent(), printf("Pushing frame level %d\n", pFrame->cnt);
    		#endif
    		pFrame->pParentFrame = pParentFrame;
    		*ppThreadFrame = pFrame;
    	}
    }
     
    /*
    Pop a frame from the frame stack
    -------------------------------- 
    Does not delete the popped frame (but isolates it).
    No need to do it anyway, since it's supposed to be in the stack.*/
    static void PopFrame(void)
    {
    	struct frame ** const ppThreadFrame = GetFramePointerSlotForThisThread();
    	//Pop the frame
    	struct frame *pFrame = *ppThreadFrame;
    	assert(pFrame != NULL); //if fails, it's a stack underflow
    	*ppThreadFrame = pFrame->pParentFrame;
    	//Isolate it
    	pFrame->pParentFrame = NULL;
    	#if _DEBUG
    	FrameDebugIndent(), printf("Popped frame level %d\n", pFrame->cnt);
    	#endif
    }
     
     
    //
    //============================================================================
    //Frame structure manipulation functions
     
    /*
    Debug : Add an indent corresponding to the top frame counter
    ------------------------------------------------------------ */
    void FrameDebugIndent(void)
    {
    	#ifdef _DEBUG
    	int cnt = 0;
    	int i;
    	{
    		struct frame * pTopFrame = TopFrame();
    		if(pTopFrame != NULL)
    			cnt = pTopFrame->cnt;
    	}
    	for(i=0 ; i<cnt ; i++)
    		putchar(' ');
    	#endif
    }
     
    static void ClearFrame(struct frame *pFrame)
    {
    	assert(pFrame!=NULL);
    	//Allow "Clearing" a frame already cleared (or for which no destructor was ever pushed.
    	if(pFrame->pDestructors != NULL)
    	{
    		//Call each destructor and delete the list
    		while(!StackOfDestructorsIsEmpty(pFrame->pDestructors))
    		{
    			struct st_destructor destr;
    			StackOfDestructorsTop(pFrame->pDestructors, &destr);
    			StackOfDestructorsPop(pFrame->pDestructors);
     
    			//Call the destructor
    			destr.proc(destr.pObj);
    		}
    		StackOfDestructorsDelete(pFrame->pDestructors), pFrame->pDestructors = NULL;
    	}
    }
     
    void InitializeFrame(struct frame *pFrame)
    {
    	assert(pFrame!=NULL);
    	assert(pFrame->pParentFrame==NULL);
     
    	//pFrame->pDestructors = StackOfDestructorsCreate(); delayed until first pushing
    	PushFrame(pFrame);
    }
    void InitializeFrameDebug(struct frame *pFrame, char const *name)
    {
    	//Debug
    	printf("Initializing frame %s\n", name);
    	InitializeFrame(pFrame);
    }
     
    void UninitializeFrameNormal(struct frame *pFrame)
    {
    	struct frame * pTopFrame = TopFrame();
    	//If pFrame is not NULL, check that it is the top one.
    	if(pFrame != NULL)
    	{
    		assert(pFrame == pTopFrame);
    	}
     
    	ClearFrame(pTopFrame);
    	PopFrame();
    }
     
    void UninitializeFrameBreak(struct frame *pFrame)
    {
    	struct frame * pTopFrame = TopFrame();
    	assert(pTopFrame != NULL);
    	//If pFrame is not NULL, check that it is the top one.
    	if(pFrame != NULL)
    	{
    		assert(pFrame == pTopFrame);
    	}
     
    	//Clear all frames until the break limit
    	while( !pTopFrame->bBreakLimit )
    	{
    		ClearFrame(pTopFrame);
    		PopFrame();
    		pTopFrame = TopFrame();
    		assert(pTopFrame != NULL); //A spurious break would lead to a stack underflow
    	}
    	//Clear the break limit too, but don't pop it unless told so
    	assert(pTopFrame->bBreakLimit);
    	ClearFrame(pTopFrame);
    	if(pTopFrame->bPopOnBreak)
    		PopFrame();
    }
     
    void UninitializeFrameReturn(struct frame *pFrame)
    {
    	struct frame * pTopFrame = TopFrame();
    	assert(pTopFrame != NULL);
    	//If pFrame is not NULL, check that it is the top one.
    	if(pFrame != NULL)
    	{
    		assert(pFrame == pTopFrame);
    	}
     
    	//Clear all frames until the return limit
    	while( !pTopFrame->bReturnLimit )
    	{
    		ClearFrame(pTopFrame);
    		PopFrame();
    		pTopFrame = TopFrame();
    		assert(pTopFrame != NULL); //A spurious return would lead to a stack underflow
    	}
    	//Clear the return limit too, and pop it
    	assert(pTopFrame->bReturnLimit);
    	ClearFrame(pTopFrame);
    	PopFrame();
    }
     
    BOOL IsTopFrameBreakLimit(struct frame *pFrame)
    {
    	struct frame * pTopFrame = TopFrame();
    	assert(pTopFrame != NULL);
    	//If pFrame is not NULL, check that it is the top one.
    	if(pFrame != NULL)
    	{
    		assert(pFrame == pTopFrame);
    	}
    	return pTopFrame->bBreakLimit;
    }
     
    BOOL IsTopFrameReturnLimit(struct frame *pFrame)
    {
    	struct frame * pTopFrame = TopFrame();
    	assert(pTopFrame != NULL);
    	//If pFrame is not NULL, check that it is the top one.
    	if(pFrame != NULL)
    	{
    		assert(pFrame == pTopFrame);
    	}
    	return pTopFrame->bReturnLimit;
    }
     
    void AddDestructor(void *pObj, DESTROYPROC proc)
    {
    	struct frame * const pTopFrame = TopFrame();
    	struct st_destructor destr;
    	destr.proc = proc;
    	destr.pObj = pObj;
     
    	assert(pTopFrame != NULL);	
     
    	if(pTopFrame->pDestructors==NULL)
    		pTopFrame->pDestructors = StackOfDestructorsCreate();
    	if(pTopFrame->pDestructors==NULL)
    		MyAbort("Destructor stack creation failed.");
    	StackOfDestructorsPush(pTopFrame->pDestructors, &destr);
    }
    Les fonctions de "StackOfDestructors" qu'utilise mon programme :
    Code C : 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
    /*
    MyStack.h:
    	Fichier d'en-tête pour une pile de destructeurs à appeler.
    */
    typedef void (*DESTROYPROC)(void *pvObj);
     
    struct st_destructor
    {
    	DESTROYPROC proc;
    	void *pObj;
    };
    struct st_stackOfDestructors;
     
    EXTERN_C struct st_stackOfDestructors * StackOfDestructorsCreate(void);
    EXTERN_C void StackOfDestructorsDelete(struct st_stackOfDestructors *pStack);
    EXTERN_C void StackOfDestructorsPush(struct st_stackOfDestructors *pStack, struct st_destructor const *pcDestr);
    EXTERN_C void StackOfDestructorsPop(struct st_stackOfDestructors *pStack);
    EXTERN_C void StackOfDestructorsTop(struct st_stackOfDestructors const *pcStack, struct st_destructor *pDestr);
    EXTERN_C BOOL StackOfDestructorsIsEmpty(struct st_stackOfDestructors const *pcStack);
    Code C++ : 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
    /*
    MyStack.cpp:
    	Ces fonctions sont un bète wrapper C++ extern "C" sur la classe vector du C++,
    	car je suis trop fainéant pour créer une classe de pile alors que c'est pas
    	là-dessus que je bosse.
    */
    #include "stdafx.h"
    #include "MyStack.h"
    #include <vector>
    #include <cassert>
     
    struct st_stackOfDestructors
    {
    public:
    	std::vector< struct st_destructor > theStack;
    };
     
    EXTERN_C struct st_stackOfDestructors * StackOfDestructorsCreate(void)
    {
    	return new struct st_stackOfDestructors;
    }
     
    EXTERN_C void StackOfDestructorsDelete(struct st_stackOfDestructors *pStack)
    {
    	//assert(pStack != NULL);
    	delete pStack;
    }
     
     
    EXTERN_C void StackOfDestructorsPush(struct st_stackOfDestructors *pStack, struct st_destructor const *pcDestr)
    {
    	assert(pStack != NULL);
    	assert(pcDestr != NULL);
    	pStack->theStack.push_back(*pcDestr);
    }
     
    EXTERN_C void StackOfDestructorsPop(struct st_stackOfDestructors *pStack)
    {
    	assert(pStack != NULL);
    	pStack->theStack.pop_back();
    }
     
    EXTERN_C void StackOfDestructorsTop(struct st_stackOfDestructors const *pcStack, struct st_destructor *pDestr)
    {
    	assert(pcStack != NULL);
    	assert(pDestr != NULL);
    	*pDestr = pcStack->theStack.back();
    }
     
    EXTERN_C BOOL StackOfDestructorsIsEmpty(struct st_stackOfDestructors const *pcStack)
    {
    	assert(pcStack != NULL);
    	bool bRet = pcStack->theStack.empty();
    	return (bRet ? TRUE : FALSE);
    }
    Et le programme qui utilise cet horrible framework :
    Code C : 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
    #include "stdafx.h"
    #include "Destructors.h"
     
    //Objet, son constructeur et son destructeur
    struct st_uneClasse
    {
    	int dummy;
    };
    static void uneClasse_constructeur(struct st_uneClasse *pObj, int val)
    {
    	assert(pObj != NULL);
    	pObj->dummy = val;
    	FrameDebugIndent(), printf("uneClasse_constructeur() : dummy=%02d\n", pObj->dummy);
    }
    static void uneClasse_destructeur(void *pvObj)
    {
    	struct st_uneClasse *pObj = pvObj;
    	FrameDebugIndent(), printf("uneClasse_destructeur()  : dummy=%02d\n", pObj->dummy);
    }
     
    //----------------------------------------------------------------------------
    //Test function
     
    EXTERN_C void TestDestructorsC(void)
    BEGIN_FUNCTION
    	int i = 42;
    	FrameDebugIndent(), puts("Bloc externe : Debut");
    	BEGIN
    		struct st_uneClasse obj;
    		FrameDebugIndent(), puts("Bloc interne : Instanciation d'un objet");
    		uneClasse_constructeur(&obj, 42), AddDestructor(&obj, uneClasse_destructeur);
     
    		FrameDebugIndent(), puts("Bloc interne : Avant le for");
    		for(i=0 ; i<10 ; i++)
    		BEGIN_LOOP
    			struct st_uneClasse obj2;
    			uneClasse_constructeur(&obj2, i), AddDestructor(&obj2, uneClasse_destructeur);
    			//FrameDebugIndent(), printf("i=%d\n", i);
    			if(i==5)
    			BEGIN
    				FrameDebugIndent(), puts("BREAKING!");
    				//BREAK
    				RETURN
    			END
    		END_LOOP
    		FrameDebugIndent(), puts("Bloc interne : Apres le for");
    	END
    	FrameDebugIndent(), puts("Bloc externe : Fin");
    END_FUNCTION
    Bonne chance !
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Je doute que tu veuilles vraiment te plonger là-dedans, mais si tu veux des détails, je t'expliquerai comment ce monstre marche.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Par défaut
    Si tu fait beaucoup d'allocations dans ton programme, tu peux aussi de créer un petit gestionnaire d'allocation qui libère alors toute la mémoire dynamique allouée par le programme lors d'un return ou exit

    J'en ai un si tu veux: ftp://ftp-developpez.com/franckh/sources/c_ansi/CMM.zip ... Y'a sans doute mieux mais il fonctionne très bien
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 299
    Par défaut
    Salut Médinoc, merci pour ton monstre, mais j'avoue que tu y es allé un peu fort...

    Franck H, je n'arrive pas à télécharger ton zip : erreur de connexion. Je réessayerai plus tard.

  10. #10
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Par défaut
    Citation Envoyé par salseropom Voir le message
    Franck H, je n'arrive pas à télécharger ton zip : erreur de connexion. Je réessayerai plus tard.
    Ha chez moi ca marche, sinon tente depuis ma page perso
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  11. #11
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Citation Envoyé par salseropom Voir le message
    Salut Médinoc, merci pour ton monstre, mais j'avoue que tu y es allé un peu fort...
    Ce n'est pourtant pas bien compliqué : Ça repose sur un principe qui m'amuse beaucoup en ce moment, la liste chaînée dans la pile système.
    • À chaque entrée de bloc, une structure est créée en variable locale. Elle est alors chaînée à la précédente (le pointeur vers la structure au sommet de la pile est conservé en variable globale ou dans du Thread-Local Storage (TLS)
    • La fonction AddDestructor() permet d'empiler un destructeur (et l'adresse de l'objet à détruire) dans la structure au sommet de la pile.
    • À chaque sortie de bloc, la structure est "dépilée", et si des destructeurs y ont été empilés, ils sont appelés.
    • Là où ça devient intéressant, c'est pour les macros BREAK et RETURN: Le code associé parcoure la liste chaînée, appelle tous les destructeurs qui s'y trouvent, et "dépile" les structures avant d'effectuer le vrai break ou return.
      • Ainsi, si l'on voulait rajouter le support d'une fonction de type exit(), il suffirait à cette fonction de parcourir entièrement la liste chaînée, appeler tous les destructeurs, puis appeler la vraie fonction exit()...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Par défaut
    Ca m'a l'air bien intéressant, surtout si ca touche aux mécanismes internes du processus et de sa gestion par rapport à l'OS mais c'est pas un peu trop spécifique ? Je veux dire par là qu'au final tout dépend un peu de l'implémentation système donc y'aurais pas un risque quant à la portabilité ?
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  13. #13
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Je ne suis pas sûr que ça dépende de grand-chose au niveau de l'implémentation système, en fait...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Non, en C il n'y a rien pour cela.
    Mais généralement, en cas d'erreur fatale irrécupérable, on ne se préoccupe pas de ça: On termine le processus, et l'OS détruit tout ce qui appartient au processus...
    Et s'il y a des choses a liberer, j'utiliserais atexit.

  15. #15
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    En effet, pour une sortie avec exit(), ça devrait marcher.
    Tiens en passant: Sais-tu si atexit() marche avec abort() ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  16. #16
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    En effet, pour une sortie avec exit(), ça devrait marcher.
    Tiens en passant: Sais-tu si atexit() marche avec abort() ?
    Non. Ni avec _Exit()/_exit(). Et c'est bien.

  17. #17
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    OK. Et oui, je suis d'accord que c'est bien.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  18. #18
    Membre éprouvé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 299
    Par défaut
    Sinon, je pourrais faire qqch du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    typedef struct
    {
      void * tab[50]; /* si je fais max 50 allocations de structure */
      char * name[50];
      int compteur; /* compte le nb d'alloc réalisées */
    } Memory;
    puis dès que j'alloue une structure

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Memory * mem=CreateMemory();
    MaStructure1 * mas=CreateMaStructure(blabla);
     
    mem->tab[mem->compteur]=mas; /* copie de pointeur */
    strcpy(mem->tab[mem->compteur],"MaStructure1");
    mem->compteur++;
    je peux me faire une fonction AddMemory(blabla); idem dès que dans mon main je fais une nouvelle allocation pour une nouvelle structure

    puis je fais un DestroyMemory(blabla); qui me détruit toute ma mémoie allouée d'un coup. Bien sûr j'aurais un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    if(strcmp(mem->name[i],"MaStructure1"))
      DestroyMaStructure1(mem->tab[i]);
    else if(strcmp(mem->name[i],"MaStructure2"))
      DestroyMaStructure2(mem->tab[i]);
    je n'ai pas non plus 36000 structure allouée (mais j'ai pas mal de structure "temporaires" appelées par mes grosses structures.

    J'envisage sinon de faire qqch comme ça. Mais j'attends d'être chez moi pour télécharger le zip de Franck H

Discussions similaires

  1. XamlReader->Load et libération de mémoire allouée
    Par tazer dans le forum Windows Presentation Foundation
    Réponses: 2
    Dernier message: 18/12/2012, 13h01
  2. [MFC] Libération de mémoire allouée.
    Par Denn's dans le forum MFC
    Réponses: 9
    Dernier message: 03/01/2008, 11h53
  3. [JVM & tomcat] Modifier la mémoire allouée
    Par sylvain_neus dans le forum Tomcat et TomEE
    Réponses: 5
    Dernier message: 22/06/2004, 09h13
  4. Processus Sql Server prend toute la mémoire vive
    Par cracosore dans le forum MS SQL Server
    Réponses: 9
    Dernier message: 19/02/2004, 17h53

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