动态分配泄漏内存?

Posted

技术标签:

【中文标题】动态分配泄漏内存?【英文标题】:Dynamic allocation leaks memory? 【发布时间】:2016-12-11 00:03:58 【问题描述】:
bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName)

    DWORD dwElements;

    TMobTable *pTable = (TMobTable *) zObj.GetBuffer();

    for(DWORD i = 0; i < dwElements; ++i, ++pTable)
    
        TMobTable *pNonPlayerData = new TMobTable;
        memcpy(pNonPlayerData, pTable, sizeof(TMobTable));
        m_NonPlayerDataMap.insert(TNonPlayerDataMap::value_type(pNonPlayerData->dwVnum, pNonPlayerData));
    

    return true;

我的问题是:我做错了什么?这会泄漏大量内存。每次调用此函数后,应用程序使用量增加 10MB。

【问题讨论】:

任何时候你有一个new,你需要一个delete。我没有看到你使用delete 不要尝试自己使用newdelete。这样可以避免你遇到很多麻烦和悲伤。 如果map::insert 失败,此代码将泄漏内存。如果您要使用map 在映射中存储指向动态内存的指针,并且假设map.insert 可以工作,则永远不要编写这样的代码。如果映射中的键值已经存在,那么你就有了泄漏。 dwElements 在哪里初始化? 不要破坏你自己的问题。这是不允许的。 【参考方案1】:

问题不在于这个函数。问题在于您处理m_NonPlayerDataMap 的方式。此函数将某些对象的所有权转移到该映射,当映射完成时,该映射对delete 负责。我敢打赌不会。

顺便说一句,为了避免这种问题不要这样做。除非你真的需要,否则不要使用new。相反,使地图成为的地图,而不是指针的地图。如果你想不出任何方法来实现这一点,至少使用智能指针而不是原始指针。

【讨论】:

比这更糟糕。如果 map::insert 由于映射中已经存在的密钥而失败,则保证泄漏。【参考方案2】:

使用智能指针包装器为您处理内存管理,例如:

如果使用 C++11 之前的版本:

#include <memory>

// std::auto_ptr is not container-safe!
typedef std::map<DWORD, TMobTable*> TNonPlayerDataMap;
TNonPlayerDataMap m_NonPlayerDataMap;

...

bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName)

    DWORD dwElements = ...;
    ...

    // I'm assuming this just returns a pointer to an existing memory
    // buffer and is not actually allocating a new buffer.  If it is,
    // you need to free it when you are done copying it...
    //
    TMobTable *pTable = (TMobTable *) zObj.GetBuffer();

    for(DWORD i = 0; i < dwElements; ++i, ++pTable)
    
        std::auto_ptr<TMobTable> pNonPlayerData(new TMobTable);

        // don't use memcpy! better would be to give TMobTable a copy constructor instead...
        // std::auto_ptr<TMobTable> pNonPlayerData(new TMobTable(*pTable));
        //
        *pNonPlayerData = *pTable;

        // if successful, release local ownership of the object.
        // if failed, ownership will remain here and free the object when the auto_ptr goes out of scope.
        //
        if (m_NonPlayerDataMap.insert(std::make_pair(pNonPlayerData->dwVnum, pNonPlayerData.get())).second)
            pNonPlayerData.release();
    

    return true;

或者,如果您使用的是 C++11 或更高版本:

#include <memory>

// std::unique_ptr is container-safe!
typedef std::map<DWORD, std::unique_ptr<TMobTable>> TNonPlayerDataMap;
TNonPlayerDataMap m_NonPlayerDataMap;

...

bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName)

    DWORD dwElements = ...;
    ...

    // I'm assuming this just returns a pointer to an existing memory
    // buffer and is not actually allocating a new buffer.  If it is,
    // you need to free it when you are done copying it...
    //
    TMobTable *pTable = (TMobTable *) zObj.GetBuffer();

    for(DWORD i = 0; i < dwElements; ++i, ++pTable)
    
        std::unique_ptr<TMobTable> pNonPlayerData(new TMobTable);
        //
        // or, if using C++14 or later:
        // std::unique_ptr<TMobTable> pNonPlayerData = std::make_unique<TMobTable>();

        // don't use memcpy! better would be to give TMobTable a copy constructor instead...
        // std::unique_ptr<TMobTable> pNonPlayerData(new TMobTable(*pTable));
        // std::unique_ptr<TMobTable> pNonPlayerData = std::make_unique<TMobTable>(*pTable);
        //
        *pNonPlayerData = *pTable;

        // if successful, ownership of the object is transferred into the map.
        // if failed, ownership will remain here and free the object when the unique_ptr goes out of scope.
        //
        m_NonPlayerDataMap.insert(std::make_pair(pNonPlayerData->dwVnum, std::move(pNonPlayerData)));
    

    return true;

【讨论】:

以上是关于动态分配泄漏内存?的主要内容,如果未能解决你的问题,请参考以下文章

Dynamically allocated memory 动态分配内存mallocMemory leaks 内存泄漏

处理因方法内部动态分配而导致的内存泄漏,而不会影响信号/插槽机制

动态内存分配

在C中释放动态分配的内存

为啥我们不能在堆栈上分配动态内存?

内存的动态分配(指针数组)