Привет!
Может для кого-то это очевидно, но я раньше мучался этой проблемой.
Суть в том, что когда в функции создаются несколько обьектов, выделяется для них память.
И вдруг возникает какая либо неприятность (памяти не хватило, файла нет и т.п. )
Нужно корретно выйти из функции, осободив все ранее созданные обьекты.
например:
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 без везких оснований...
Истина всегда где-то посередине.