Можно ли освободить 'void *'? - PullRequest
25 голосов
/ 02 февраля 2010
struct foo
{
    int a;
    int b;
};

void* p = (void*)malloc(sizeof(struct foo));
((foo*)p)->a;//do something.
free(p);//Is this safe?

Ответы [ 8 ]

34 голосов
/ 02 февраля 2010

Да.

malloc возвращает void *, а free занимает void *, поэтому некоторые ваши приведения бессмысленны, и вы всегда освобождаете void *, даже если начинаете с какого-либо другого рода указателей.

14 голосов
/ 02 февраля 2010

Да, это безопасно.При выделении памяти библиотека времени выполнения отслеживает размер каждого выделения.Когда вы вызываете free (), он ищет адрес, и если он находит выделение для этого адреса, освобождается правильный объем памяти (блок, выделенный по этому адресу).

6 голосов
/ 02 февраля 2010

Да - free переводит указатель на void, поэтому при его вызове указатель (неявно) приводится к указателю на void в любом случае.

Остальная часть вашего кода не так безопасна:

void* p = (void*)malloc(sizeof(foo));

Вы должны не разыграть возврат из malloc (в C). Это может скрыть ошибку забвения до #include <stdlib.h>

3 голосов
/ 02 февраля 2010

в C это совершенно безопасно, потому что нет деструкторов для вызова.

система памяти отслеживает размер их выделения.

в c ++ вы должны удалить тот же тип, что и новый, включая использование оператора delete [] для удаления новых массивов.

это просто для того, чтобы убедиться, что деструкторы вызваны.

3 голосов
/ 02 февраля 2010

Да. Прототип функции для free четный:

void free(void *ptr);
2 голосов
/ 02 февраля 2010

Возможно, он не чувствует себя безопасным из-за магии, происходящей за кулисами.Среда выполнения C и / или сама ОС активно отслеживают память, возвращаемую malloc, включая ее размер и местоположение.Посмотрите, хотя вы чувствуете, что передаете freeless-указатель обратно в free (), фактически вы возвращаете ссылку на объект, который активно отслеживает менеджер памяти.

1 голос
/ 02 февраля 2010

да, это безопасно.

0 голосов
/ 03 января 2017

Да, но обычно это признак плохого дизайна. malloc () обычно используется для выделения буферов (большие массивы одного и того же примитивного типа) или объектов (структуры с инициализированными полями). В обоих случаях malloc и free должны совпадать, поэтому

  unsigned char *rgba_buffer = malloc(width * hieght * 4);
  /* use the buffer here */
  free(rgba_buffer);

  BITSTREAM *bs = bitstream("bitfile.boin");
  /* use the bitstream here */
  destroy_bitstream(bs);

  typedef struct
  {
     FILE *fp;
     unsigned char ch;
     int index;
  } BITSTREAM;


  BITSTREAM *bitstream(const char *filename)
  {
      BITSTREAM *bs = malloc(sizeof(BITSTREAM));
      bs->fp = fopen(filename "rb");
      /* etc */
      return bs;
  }

  void destroybitstream(BITSTREAM *bs)
  {
     if(bs)
     {
        if(bs->fp)
          fclose(bs->fp);
        free(bs);
     }
  }

В одном случае malloc и free match, в другом возвращается выделенная память, имеются также вторичные ресурсы, а также конструктор и деструктор. Редко следует выделять область памяти, но не знать, для чего она используется. И вы не должны чередовать распределения и хаотически освобождать.

Современный C ++ усиливает это с помощью уникальных указателей, которые «владеют» объектом. Хотя у вас может быть уникальный указатель на void, это будет очень редко.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...