Call to _freea really necessary?

2019-04-06 14:18发布

I am developping on Windows with DevStudio, in C/C++ unmanaged.

I want to allocate some memory on the stack instead of the heap because I don't want to have to deal with releasing that memory manually (I know about smart pointers and all those things. I have a very specific case of memory allocation I need to deal with), similar to the use of A2W() and W2A() macros.

_alloca does that, but it is deprecated. It is suggested to use malloca instead. But _malloca documentation says that a call to ___freea is mandatory for each call to _malloca. It then defeats my purpose to use _malloca, I will use malloc or new instead.

Anybody knows if I can get away with not calling _freea without leaking and what the impacts are internally?

Otherwise, I will end-up just using deprecated _alloca function.

6条回答
Root(大扎)
2楼-- · 2019-04-06 14:46

To allocate memory on the stack, simply declare a variable of the appropriate type and size.

查看更多
虎瘦雄心在
3楼-- · 2019-04-06 14:50

I answered this before, but I'd missed something fundamental that meant that it only worked in debug mode. I moved the call to _malloca into the constructor of a class that would auto-free.

In debug this is fine, as it always allocates on the heap. However, in release, it allocates on the stack, and upon returning from the constructor, the stack pointer has been reset, and the memory lost.

I went back and took a different approach, resulting in a combination of using a macro (eurgh) to allocate the memory and instantiate an object that will automatically call _freea on that memory. As it's a macro, it's allocated in the same stack frame, and so will actually work in release mode. It's just as convenient as my class, but slightly less nice to use.

I did the following:

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 );

This way I can allocate using the following macro call, and it's released when the instantiated class goes out of scope:

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

My apologies for posting something that was plainly wrong!

查看更多
劳资没心,怎么记你
4楼-- · 2019-04-06 14:51

Another thing to consider is using an RAII class to manage the allocation - of course that's only useful if your macro (or whatever) can be restricted to C++.

If you want to avoid hitting the heap for performance reasons, take a look at the techniques used by Matthew Wilson's auto_buffer<> template class (http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html). This will allocate on the stack unless your runtime size request exceeds a size specified at compiler time - so you get the speed of no heap allocation for the majority of allocations (if you size the template right), but everything still works correctly if your exceed that size.

Since STLsoft has a whole lot of cruft to deal with portability issues, you may want to look at a simpler version of auto_buffer<> which is described in Wilson's book, "Imperfect C++".

I found it quite handy in an embedded project.

查看更多
做自己的国王
5楼-- · 2019-04-06 14:55

It is always important to call _freea after every call to _malloca.

_malloca is like _alloca, but adds some extra security checks and enhancements for your protection. As a result, it's possible for _malloca to allocate on the heap instead of the stack. If this happens, and you do not call _freea, you will get a memory leak.

In debug mode, _malloca ALWAYS allocates on the heap, so also should be freed.

Search for _ALLOCA_S_THRESHOLD for details on how the thresholds work, and why _malloca exists instead of _alloca, and it should make sense.


Edit:

There have been comments suggesting that the person just allocate on the heap, and use smart pointers, etc.

There are advantages to stack allocations, which _malloca will provide you, so there are reasons for wanting to do this. _alloca will work the same way, but is much more likely to cause a stack overflow or other problem, and unfortunately does not provide nice exceptions, but rather tends to just tear down your process. _malloca is much safer in this regard, and protects you, but the cost is that you still need to free your memory with _freea since it's possible (but unlikely in release mode) that _malloca will choose to allocate on the heap instead of the stack.

If your only goal is to avoid having to free memory, I would recommend using a smart pointer that will handle the freeing of memory for you as the member goes out of scope. This would assign memory on the heap, but be safe, and prevent you from having to free the memory. This will only work in C++, though - if you're using plain ol' C, this approach will not work.

If you are trying to allocate on the stack for other reasons (typically performance, since stack allocations are very, very fast), I would recommend using _malloca and living with the fact that you'll need to call _freea on your values.

查看更多
走好不送
6楼-- · 2019-04-06 14:58

If you're using _malloca() then you must call _freea() to prevent memory leak because _malloca() can do the allocation either on stack or heap. It resorts to allocate on heap if the given size exceeds_ALLOCA_S_THRESHOLD value. Thus, it's safer to call _freea() which won't do anything if allocation happened on stack.

If you're using _alloca() which seems to be deprecated as of today; there is no need to call _freea() as the allocation happens on stack.

查看更多
干净又极端
7楼-- · 2019-04-06 15:10

If your concern is having to free temp memory, and you know all about things like smart-pointers then why not use a similar pattern where memory is freed when it goes out of scope?

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
}
查看更多
登录 后发表回答