Выход из функции при ошибке
От: menify Россия  
Дата: 26.12.02 09:03
Оценка:
Привет!

Может для кого-то это очевидно, но я раньше мучался этой проблемой.
Суть в том, что когда в функции создаются несколько обьектов, выделяется для них память.
И вдруг возникает какая либо неприятность (памяти не хватило, файла нет и т.п. )

Нужно корретно выйти из функции, осободив все ранее созданные обьекты.

например:

MSG*    new_msg(..)
{
    MSG*        msg;
    HEADER*     header;
    ADDR*       to;
    ADDR*       from;
    char*       body;
    
    header = (HEADER*) malloc( sizeof(HEADER) );
    if (header == NULL)
    {
        return NULL;
    }
    
    ...
    
    to = (ADDR*)malloc( sizeof(ADDR) );
    if (to == NULL)
    {
        free( header );                 // !!!
        return NULL;
    }
    
    ...
    
    from = (ADDR*)malloc( sizeof(ADDR) );
    if (from == NULL)
    {
        free( to );                     // !!!
        free( header );                 // !!!
        return NULL;
    }
    
    ...
    
    msg = (ADDR*)malloc( sizeof(MSG) );
    if (msg == NULL)
    {
        free( body );                   // !!!
        free( from );                   // !!!
        free( to );                     // !!!
        free( header );                 // !!!
        return NULL;
    }
 
    ...
    
    return msg;
}


По моему это не очень красивый и надежный метод. Елементарно можно забыть где-нибудь поставить free(..)
Много разных идей было как сделать "красивый" и надежный код.
И вот осенило — нужно вкусить "запретный плод" — goto
До этого свято веря, что все можно сделать и без него, даже елегантнее.

С помощью goto будет так:

MSG*    new_msg(..)
{
    MSG*        msg;
    HEADER*     header;
    ADDR*       to;
    ADDR*       from;
    char*       body;
    
    
    header = (HEADER*) malloc( sizeof(HEADER) );
    if (header == NULL)
    {
        goto label_fail_new_header;
    }
    
    ...
    
    to = (ADDR*)malloc( sizeof(ADDR) );
    if (to == NULL)
    {
        goto label_fail_new_to;
    }
    
    ...
    
    from = (ADDR*)malloc( sizeof(ADDR) );
    if (from == NULL)
    {
        goto label_fail_new_from;
    }
    
    ...
    
    msg = (ADDR*)malloc( sizeof(MSG) );
    if (msg == NULL)
    {
        goto label_fail_new_msg;
    }
 
    ...
    
    return msg;
    
    
    //-------------------------------------------------------//
    //          LABELS:                                      //
    
    label_fail_new_msg:
        free( body );                   // !!!
    label_fail_new_body:
        free( from );                   // !!!
    label_fail_new_from:
        free( to );                     // !!!
    label_fail_new_to:
        free( header );                 // !!!
    label_fail_new_header:
        
        return NULL;
}


Я это написал, потому-что может это кому-нибудь будет полезным.
Может кто-то предложит такой-же эффективный метод, но без goto?


А еще goto классно работает когда нужно быстро выйти из функции при этом что-то выполнив на последок

Главное не переуседствовать и не тыкать goto без везких оснований...

Истина всегда где-то посередине.
Всего доброго.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.