调用_freea 真的有必要吗?

Posted

技术标签:

【中文标题】调用_freea 真的有必要吗?【英文标题】:Call to _freea really necessary? 【发布时间】:2010-10-18 14:29:23 【问题描述】:

我正在使用 DevStudio 在 Windows 上以非托管的 C/C++ 进行开发。

我想在堆栈而不是堆上分配一些内存,因为我不想手动释放该内存(我知道智能指针和所有这些事情。我有一个非常具体的内存案例我需要处理的分配),类似于使用 A2W() 和 W2A() 宏。

_alloca 会这样做,但已被弃用。建议改用 malloca。但是 _malloca 文档说每次调用 _malloca 都必须调用 ___freea。然后它破坏了我使用 _malloca 的目的,我将使用 malloc 或 new。

任何人都知道我是否可以不调用 _freea 而不泄漏以及内部影响是什么?

否则,我最终将只使用已弃用的 _alloca 函数。

【问题讨论】:

请注意,_alloca 的弃用不是基于“将在未来版本的 CRT 中删除”,而是因为“存在更安全的替代品”。与旨在提供过渡期的弃用不同,此类弃用用于提高对可能问题的认识的特定目的。我会说,如果您知道大小不会很大,只需使用 _alloca。 【参考方案1】:

如果您使用_malloca(),那么您必须调用_freea() 以防止内存泄漏,因为_malloca() 可以在堆栈或堆上进行分配。如果给定大小超过_ALLOCA_S_THRESHOLD 值,它会在堆上分配。因此,调用_freea() 更安全,如果分配发生在堆栈上,它不会做任何事情。

如果您使用的是_alloca(),从今天起似乎已被弃用;由于分配发生在堆栈上,因此无需调用 _freea()

【讨论】:

【参考方案2】:

我之前回答过这个问题,但我错过了一些基本的东西,这意味着它只能在调试模式下工作。我将对 _malloca 的调用移到一个可以自动释放的类的构造函数中。

在调试中这很好,因为它总是在堆上分配。但是在release的时候是在栈上分配的,从构造函数返回后,栈指针被重置,内存丢失了。

我返回并采用了不同的方法,结果结合使用宏 (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 );

对于发布明显错误的内容,我深表歉意!

【讨论】:

【参考方案3】:

要考虑的另一件事是使用 RAII 类来管理分配 - 当然,这只有在您的宏(或其他)可以限制为 C++ 时才有用。

如果您出于性能原因想避免撞到堆,请查看 Matthew Wilson 的 auto_buffer<> 模板类 (http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html) 使用的技术。这将在堆栈上分配,除非您的运行时大小请求超过编译器时指定的大小 - 因此您可以获得大多数分配的无堆分配速度(如果您正确调整模板大小),但如果超过那个尺寸。

由于 STLsoft 在处理可移植性问题方面有很多麻烦,您可能需要查看在 Wilson 的书中描述的 auto_buffer<> 的更简单版本,"Imperfect C++".

我发现它在嵌入式项目中非常方便。

【讨论】:

对 auto_buffer 建议+1。它基本上是在做 _malloca 所做的,而不是 Windows 上的 _alloca。有一项检查可确保您不会超出堆栈限制,并且如果需要,它将进行堆分配而不是堆栈分配。不过,这也适用于 C。【参考方案4】:

在每次调用 _malloca 之后调用 _freea 总是很重要的。

_malloca 与 _alloca 类似,但为您的保护添加了一些额外的安全检查和增强功能。因此,_malloca 可以在堆而不是堆栈上进行分配。如果发生这种情况,而您没有调用 _freea,则会发生内存泄漏。

在调试模式下,_malloca 总是在堆上分配,所以也应该被释放。

搜索 _ALLOCA_S_THRESHOLD 以了解有关阈值如何工作的详细信息,以及为什么存在 _malloca 而不是 _alloca,这应该是有意义的。


编辑:

已经有 cmets 建议这个人只是在堆上分配,并使用智能指针等。

堆栈分配有很多优点,_malloca 将为您提供,所以有理由想要这样做。 _alloca 将以相同的方式工作,但更有可能导致堆栈溢出或其他问题,不幸的是它没有提供很好的异常,而是倾向于仅仅破坏你的进程。 _malloca 在这方面更安全,并且可以保护您,但代价是您仍然需要使用 _freea 释放内存,因为 _malloca 可能(但在释放模式下不太可能)选择在堆上而不是在堆栈上分配。

如果您的唯一目标是避免释放内存,我建议您使用智能指针,以便在成员超出范围时为您处理内存释放。这将在堆上分配内存,但要安全,并防止您不得不释放内存。不过,这只适用于 C++ - 如果您使用的是普通的 C,这种方法将不起作用。

如果您出于其他原因尝试在堆栈上分配(通常是性能,因为堆栈分配非常非常快),我建议您使用 _malloca 并接受这样一个事实,即您需要在您的值上调用 _freea .

【讨论】:

只是好奇,但为什么对 Mitch 和我的帖子投反对票?我想知道为什么有人不同意这个评论......尤其是如果我遗漏了什么。【参考方案5】:

如果您担心必须释放临时内存,并且您对智能指针之类的事情了如指掌,那么为什么不使用类似的模式来释放超出范围的内存呢?

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

【讨论】:

【参考方案6】:

要在堆栈上分配内存,只需声明一个适当类型和大小的变量。

【讨论】:

这不是我的反对意见,但我猜只是因为他专门询问 _alloca/_malloca,它们的堆栈使用模式与标准变量声明非常不同。不过,就我个人而言,我也会投票给你,因为在大多数情况下,如果可能的话,我会这样做。 您不能使用简单的变量在堆栈上动态分配内存块。例如, unsigned char dataBlock[tempStorageSize] 不会编译。它需要在编译时知道分配块的大小。 @philibertperusse :我知道这一点。发帖者最初询问如何在堆栈上分配。

以上是关于调用_freea 真的有必要吗?的主要内容,如果未能解决你的问题,请参考以下文章

STM32F411:清除外部中断标志真的有必要吗?

基类构造函数真的在派生类构造函数之前调用吗

你真的了解[super ]关键字吗?

真的有必要用rxjava吗

CUDA 真的没有类似 calloc() 的 API 调用吗?

一个函数中 有return后有必要用exit吗