Правила программирования на С и С++. Главы 1-6 - Помещайте код, динамически распределяющий и освобождающий память, в одном и том же месте

ОГЛАВЛЕНИЕ

 

73. Помещайте код, динамически распределяющий и освобождающий память, в одном и том же месте.

Утечки памяти - выделенную память забыли освободить- являются большой проблемой в приложениях, продолжительность работы которых не ограничена: серверах баз данных, торговых автоматах, операционных системах и так далее. Имеется множество способов для того, чтобы отслеживать эту проблему. Многие программы, например, модифицируют функцию malloc() для создания списка выделенных областей памяти, который может просматриваться функцией free() для проверки задействованных указателей. Вы также можете доработать заголовочный файл, необходимый для сопровождения списка выделенных областей памяти, путем помещения туда информации о том, откуда было произведено выделение памяти. (Передайте __LINE__ и _FILE__ в свою отладочную версию malloc()). Список выделенных областей памяти должен быть пуст при завершении работы программы. Если он не пуст, то вы можете его просмотреть и, по крайней мере, разобраться, где была выделена эта память.

Отслеживание - это хорошо, но предупреждение лучше. Если есть возможность, то вы должны размещать free() в той же функции, где сделан соответствующий вызов malloc(). Например, используйте это:

void user( void )

{

p = malloc( size );

producer( p );

consumer( p );

free( p );

}

void пользователь( void )

{

p = malloc( size );

изготовитель( p );

потребитель( p );

free( p );

}

вместо этого:

void *producer( )

{

void *p = malloc( size );

// ...

return p;

}

void consumer( void *p )

{

// ...

free( p );

}

void user( void )

{

void *p = producer();

consumer( p );

}

void *изготовитель( )

{

void *p = malloc( size );

// ...

return p;

}

void потребитель( void *p )

{

// ...

free( p );

}

void пользователь( void )

{

void *p = изготовитель();

потребитель( p );

}

Несмотря на это, вы не сможете всегда делать подобное на С. Например, предыдущие правила о неинициализированных переменных относятся и к памяти, выделенной malloc(). Лучше сделать так:

some_object *p = allocate_and_init(); // Не возвращает значения, если // памяти недостаточно.некий_объект *p = выделить_и_инициализировать(); // Не возвращает значения, если
памяти недостаточно. чем так: some_object *p = malloc( sizeof(some_object) );

if ( !p )

fatal_error("Недостаточно памяти!");init();

некий_объект *p = malloc( sizeof(некий_объект) );

if ( !p )

фатальная_ошибка("Недостаточно памяти!");инициализировать();В С++ эта проблема решается при помощи конструкторов.