C++向量和内存泄漏

4

我曾经在某个时间看到过一篇文章,提到向量会根据它们的使用方式导致内存泄漏,但是为了确认一下,我想问一下:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

int main()
{
    vector<somePtr*> listPtrs;

    return 0;
    //Detects memory leaks
}

而这并没有检测到任何东西:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

int main()
{
    {
        vector<somePtr*> listPtrs;
    }

    return 0;
    //No memory leaks detected
}

向量中的对象将在清除指针之前被删除。我记得读过向量、列表和其他std容器在它们所在的块自动删除,所以在例1中,由于内存泄漏函数在块结束之前调用,因此向量仍然存活并导致内存泄漏。
我不太确定,因为我已经很久没有看到这个问题了,而且我只能找到有关未删除对象的问题,只是移除指针。
这是真的吗?如果我使用包含向量和列表的全局类,会产生内存泄漏吗?

10
std::vector并不会导致内存泄漏,粗心的程序员才会。 - Captain Obvlious
3
你还应该包括一个实际展示你所经历的行为的例子,包括对CRT调试API的调用。很有可能你是基于报告泄漏的时间错误地解释了它们。 - Captain Obvlious
你展示的这两个样例中都没有内存泄漏。 - juanchopanza
2个回答

12

在调用_CrtDumpMemoryLeaks的时机很重要,因为并非所有已使用的内存都可能已经被释放。例如,在下面的示例中,如果在listPtrs超出范围之前调用_CrtDumpMemoryLeaks(),它分配的任何内存都将包含在泄漏内存列表中。

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <vector>

int main()
{
    std::vector<struct Foo*> listPtrs;

    _CrtDumpMemoryLeaks();

    return 0;
}
在下面的示例中,listPtrs在调用_CrtDumpMemoryLeaks之前就超出了其作用域,因此它分配的任何内存都将被释放,而不会列在泄漏内存块中。
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <vector>

int main()
{
    {
        std::vector<struct Foo*> listPtrs;
    }

    _CrtDumpMemoryLeaks();

    return 0;
}
同样的,如果您在 main 函数返回之后调用 _CrtDumpMemoryLeaks,则应释放由 std::vector 分配的任何资源。这是因为 listPtrs 已经超出了作用域,std::vector 的析构函数已被调用。
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <vector>

// Call _CrtDumpMemoryLeaks after main has returned and before program terminates.
struct AtExit
{
    ~AtExit() { _CrtDumpMemoryLeaks(); }
} doAtExit;

int main()
{
    std::vector<struct Foo*> listPtrs;

    return 0;
}

我强烈建议使用智能指针代替裸指针。这会让它们在冬天保持温暖,而且您也不必担心使用 delete

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <vector>
#include <memory>

// Call _CrtDumpMemoryLeaks after main has returned and before program terminates.
struct AtExit
{
    ~AtExit() { _CrtDumpMemoryLeaks(); }
} doAtExit;

int main()
{
    std::vector<std::unique_ptr<struct Foo*>> listPtrs;

    return 0;
}

1
“它让他们在冬天保持温暖”这句话让我有些费解。我不得不思考一会儿才意识到自己错过了显而易见的东西。 - Twisted Code

1
在两段代码中,您在堆栈上分配了vector<>。因此,当它超出范围时,vector的析构函数将被调用。我不知道您使用的泄漏检测器是什么,但如果它在main函数退出之前检查泄漏,它可能会检测到泄漏,但这并不是真正的泄漏。
在内存泄漏方面,您会遇到问题,因为std::vector析构函数不会对向量中的项目调用delete,尽管它会调用它们的析构函数。因此,vector<int>vector<MyClass>都是可以的,因为向量保存了实际对象并调用了其析构函数。另一方面,如果您有vector<MyClass*>,则需要小心;删除向量将不会释放与其指向的MyClass对象相关联的内存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接