Позвонить на _freea действительно необходимо? - PullRequest
8 голосов
/ 09 апреля 2009

Я работаю в Windows с DevStudio, в C / C ++ неуправляем.

Я хочу выделить некоторую память в стеке вместо кучи, потому что я не хочу иметь дело с освобождением этой памяти вручную (я знаю об умных указателях и всех этих вещах. У меня очень специфический случай памяти Распределение, с которым мне нужно иметь дело), ​​аналогично использованию макросов A2W () и W2A ().

_alloca делает это, но не рекомендуется. Вместо этого рекомендуется использовать malloca . Но в документации _malloca говорится, что вызов ___ freea обязателен для каждого вызова _malloca. Затем он побеждает мою цель использовать _malloca, вместо этого я буду использовать malloc или new.

Кто-нибудь знает, смогу ли я обойтись без звонка _freea без утечки, и каковы будут внутренние последствия?

В противном случае я получу в итоге только устаревшую функцию _alloca.

Ответы [ 6 ]

13 голосов
/ 09 апреля 2009

Всегда важно вызывать _freea после каждого вызова _malloca.

_malloca похож на _alloca, но добавляет некоторые дополнительные проверки безопасности и улучшения для вашей защиты. В результате, _malloca может размещаться в куче, а не в стеке. Если это произойдет, и вы не вызовете _freea, вы получите утечку памяти.

В режиме отладки _malloca ВСЕГДА выделяется в куче, поэтому также должен быть освобожден.

Найдите в _ALLOCA_S_THRESHOLD подробности о том, как работают пороги и почему _malloca существует вместо _alloca, и это должно иметь смысл.


Редактировать:

Были комментарии, предлагающие, чтобы человек просто выделял кучу, использовал умные указатели и т. Д.

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

Если ваша единственная цель - избежать освобождения памяти, я бы порекомендовал использовать умный указатель, который будет обрабатывать освобождение памяти для вас, когда член выходит из области видимости. Это выделит память в куче, но будет безопасным и избавит вас от необходимости освобождать память. Однако это будет работать только в C ++ - если вы используете обычный старый C, этот подход не будет работать.

Если вы пытаетесь выделить в стеке по другим причинам (обычно это производительность, поскольку распределение в стеке очень и очень быстро), я бы порекомендовал использовать _malloca и учитывать тот факт, что вам нужно будет вызывать _freea для ваших значений .

3 голосов
/ 09 апреля 2009

Еще одна вещь, которую следует учитывать, - это использование класса RAII для управления распределением - конечно, это полезно, только если ваш макрос (или любой другой) может быть ограничен C ++.

Если вы хотите избежать попадания в кучу по соображениям производительности, взгляните на методы, используемые шаблонным классом auto_buffer<> Мэтью Уилсона (http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html). Это будет выделять в стеке, если ваш запрос размера во время выполнения не превышает размер, указанный во время компиляции - так что вы получаете скорость без выделения кучи для большинства выделений (если вы правильно выбрали размер шаблона), но все по-прежнему работает правильно, если вы превысите этот размер.

Поскольку в STLsoft много трудностей, связанных с переносимостью, вы можете рассмотреть более простую версию auto_buffer<>, описанную в книге Уилсона, «Несовершенный С ++».

Мне показалось, что это удобно во встроенном проекте.

1 голос
/ 22 августа 2013

Я отвечал на это раньше, но я упустил нечто фундаментальное, что означало, что это работало только в режиме отладки. Я переместил вызов _malloca в конструктор класса, который автоматически освобождается.

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

Я вернулся и выбрал другой подход, в результате чего было использовано сочетание использования макроса (eurgh) для выделения памяти и создания объекта, который будет автоматически вызывать _freea в этой памяти. Поскольку это макрос, он размещен в одном и том же стековом фрейме и поэтому фактически будет работать в режиме выпуска. Это так же удобно, как и мой класс, но чуть менее приятно использовать.

Я сделал следующее:

class EXPORT_LIB_CLASS CAutoMallocAFree
{
public:
    CAutoMallocAFree( void *pMem ) : m_pMem( pMem ) {}
    ~CAutoMallocAFree() { _freea( m_pMem ); }

private:
    void    *m_pMem;

    CAutoMallocAFree();
    CAutoMallocAFree( const CAutoMallocAFree &rhs );
    CAutoMallocAFree &operator=( const CAutoMallocAFree &rhs );
};

#define AUTO_MALLOCA( Var, Type, Length ) \
    Type* Var = (Type *)( _malloca( ( Length ) * sizeof ( Type ) ) ); \
    CAutoMallocAFree __MALLOCA_##Var( (void *) Var );

Таким образом, я могу выделить с помощью следующего вызова макроса, и он освобождается, когда экземпляр класса выходит из области видимости:

            AUTO_MALLOCA( pBuffer, BYTE, Len );
            Ar.LoadRaw( pBuffer, Len );

Мои извинения за публикацию чего-то, что было явно неправильно!

1 голос
/ 09 апреля 2009

Чтобы выделить память в стеке, просто объявите переменную соответствующего типа и размера.

0 голосов
/ 08 мая 2017

Если вы используете _malloca(), то вы должны вызвать _freea(), чтобы предотвратить утечку памяти, потому что _malloca() может выполнить выделение либо в стеке, либо в куче. Он прибегает к выделению в куче, если заданный размер превышает значение_ALLOCA_S_THRESHOLD. Таким образом, безопаснее вызывать _freea(), который ничего не сделает, если распределение произошло в стеке.

Если вы используете _alloca(), что кажется устаревшим на сегодняшний день; нет необходимости вызывать _freea(), поскольку распределение происходит в стеке.

0 голосов
/ 09 апреля 2009

Если вас беспокоит необходимость освободить временную память, и вы знаете все о таких вещах, как умные указатели, то почему бы не использовать аналогичный шаблон, когда память освобождается, когда она выходит из области видимости?

template <class T>
class TempMem
{
  TempMem(size_t size)
  {
    mAddress = new T[size];
  }

  ~TempMem
  {
    delete [] mAddress;
  }

  T* mAddress;
}

void foo( void )
{
  TempMem<int> buffer(1024);

  // alternatively you could override the T* operator..
  some_memory_stuff(buffer.mAddress);

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