J'ai un morceau de code qui ressemble presque à ce (ce qui est simplifié juste pour montrer la structure):Le bon modèle pour la séquence des allocations et des opérations qui peut échouer
int Ugly_Calculation(void)
{
type1 *X1 = type1_new();
if (!X1) return 0;
type2 *X2 = type2_new(X1);
if (!X2) return 0;
type3 *X3 = type3_new(X1, X2);
if (!X3) return 0;
int result = PerformCalculation(X1, X2, X3);
free(X3);
free(X2);
free(X1);
return result;
}
Il alloue des objets et usages les pour un calcul et libère les objets. Les fonctions typeX_new retournent souvent zéro, donc la mémoire n'est généralement pas libérée correctement.
Dans ma première itération, j'ai réécrit le code de manière suivante:
typedef struct
{
type1 *X1;
type2 *X2;
type3 *X3;
} ugly_context;
void free_ctx(ugly_context *ctx)
{
free(ctx->X1);
free(ctx->X2);
free(ctx->X3);
}
int Ugly_Calculation(void)
{
ugly_context ctx = {NULL, NULL, NULL};
ctx->X1 = type1_new();
if (!ctx->X1)
{
free_ctx(&ctx);
return 0;
}
ctx->X2 = type1_new(ctx->X1);
if (!ctx->X2)
{
free_ctx(&ctx);
return 0;
}
ctx->X3 = type1_new(ctx->X1, ctx->X2);
if (!ctx->X3)
{
free_ctx(&ctx);
return 0;
}
int result = PerformCalculation(X1, X2, X3);
free_ctx(&ctx);
return result;
}
Ma première solution est sûre, mais il a perdu la lisibilité du code d'origine. Ma deuxième idée suit:
type2 *type2_new_check(type1 *X1)
{
type2 *result = NULL;
if (X1)
{
result = type2_new(X1);
}
return result;
}
type3 *type3_new_check(type1 *X1, type2 *X2)
{
type3 *result = NULL;
if (X1 && X2)
{
result = type3_new(X1, X2);
}
return result;
}
int PerformCalculation_check(type1 *X1, type2 *X2, type3 *X3)
{
int result = 0;
if (X1 && X2 && X3)
{
result = PerformCalculation(X1, X2, X3);
}
return result;
}
int Ugly_Calculation(void)
{
type1 *X1 = type1_new();
type2 *X2 = type2_new_check(X1);
type3 *X3 = type3_new_check(X1, X2);
int result = PerformCalculation_check(X1, X2, X3);
free(X3);
free(X2);
free(X1);
return result;
}
La lisibilité du code est OK et sorties début ont disparu, mais il est assez long pour la méthode avec 3 blocs de mémoire.
Mon vrai code n'est pas 3 allocations, mais 15, donc la méthode devient très effrayante et moche. Yat-il un moyen agréable, comment résoudre ce modèle sans contrôles excessifs et libérer? (Le mieux serait de briser la méthode des parties plus petites qui sont proprement gérables par des contrôles, mais je voudrais éviter que, pour une raison quelconque)
Cela ne permettra pas à la plupart des compilateurs de rester heureux, mais de laisser les analyseurs statiques. Ils ont tendance à ne pas aimer l'assignation à l'intérieur des conditions et 'goto' à la fois. Bien que ce code soit correct, je crois qu'il existe de meilleurs moyens. – Lundin
une affectation paranthésisée est bien pour les compilateurs que je connais, et 'goto' est bien sûr aussi. –
Cependant, aucun d'eux ne passera devant un vérificateur MISRA-C. – Lundin