【问题标题】:std::list Memory Leak with interfaces带有接口的 std::list 内存泄漏
【发布时间】:2012-12-14 04:12:53
【问题描述】:

我遇到了 std::list 和内存泄漏问题:

class AbstractObject
{
    public:
        virtual void Say() = 0;
}
class RealObject : public AbstractObject
{
    public:
        virtual void Say() { cout << "Real Obj Says..." << endl; } //Do I need the "virtual" keyword here too?
}
class AnotherRealObject : public AbstractObject
{
    public:
        virtual void Say() { cout << "Another Real Obj Says..." << endl; } //Do I need the "virtual" keyword here too?
}
class PackOfObjects
{
    public:
        std::list<AbstractObject*> objects; //list of pointers because it doesn't let me create a list of an abstract class
        void Say()
        {
            for(std::list<AbstractObject*>::iterator obj = objects.begin(); obj != objects.end(); obj++)
            {
                (*obj)->Say();
            }
        }
}
int _tmain(int argc, _TCHAR* argv[])
{
    PackOfObjs myObjs;

    RealObject objA;
    myObjs.objects.push_back(&objA); //This adds 1 memory leak
    AnotherRealObject objB;
    myObjs.objects.push_back(&objB); //This adds another 1 memory leak

    _gettch();
    _CrtDumpMemoryLeaks();
    return 0;
}

仅声明了 PackOfObjs,我已经有 2 个内存泄漏,如果我删除 std::list,它们就会消失,并且对于我添加到列表中的每个地址,它们都会增加 1。 我尝试清除列表和一些在清除之前删除所有指向的 objs 的代码,但至少 2 个内存泄漏仍然存在。

由于我没有使用任何 new(甚至没有在我添加的元素上),我猜测列表本身会创建一些变量并且不会删除它们,我该如何解决这个问题?

【问题讨论】:

    标签: c++ memory-leaks interface virtual abstract-class


    【解决方案1】:

    _CrtDumpMemoryLeaks() 运行时,main 内部分配的所有对象仍然存在。你打电话给_CrtDumpMemoryLeaks() 太早了。相反,试试这个:

    int _tmain(int argc, _TCHAR* argv[])
    {
        {
            PackOfObjs myObjs;
    
            RealObject objA;
            myObjs.objects.push_back(&objA); //This adds 1 memory leak
            AnotherRealObject objB;
            myObjs.objects.push_back(&objB); //This adds another 1 memory leak
    
            // <- all memory used by the list is freed here
        }
        _gettch();
        _CrtDumpMemoryLeaks();
        return 0;
    }
    

    我似乎记得调用_CrtDumpMemoryLeaks 的推荐方式是在全局对象的析构函数中。这对于其他全局对象来说可能还为时过早,但至少在 main 内部创建的所有对象都已经被销毁了。

    struct memory_leak_dumper
    {
        ~memory_leak_dumper(){ _CrtDumpMemoryLeaks(); }
    };
    memory_leak_dumper _dumper; // this is a global object
    

    【讨论】:

      【解决方案2】:

      要检查内存泄漏,您应该使用:

      _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

      在你的 main 开头

      将在程序退出时检查泄漏,现在您在对象仍在堆栈上时检查它们,因此您没有泄漏。

      如果您使用虚拟方法,您应该添加虚拟析构函数,尽管在您的情况下它不会导致内存泄漏,但如果您的列表将包含动态分配的对象,那么 AbstractObject 中的虚拟析构函数将是强制性的。

      至于你的问题:

      "//这里也需要"virtual"关键字吗?"

      可以,只要你的列表是基类指针类型

      【讨论】:

        【解决方案3】:

        为了扩展K-ballo's answer,技术上_CrtDumpMemoryLeaks 检查堆上的对象。虽然您没有直接在堆上分配任何东西,但 std::list(以及为此动态管理内存的所有容器)会 - 否则动态大小将不是一个选项。

        所以不,从技术上讲没有泄漏,但是在您调用 _CrtDumpMemoryLeaks 时,动态分配的内存仍在使用中,但尚未被释放。

        按照建议将std::list 包含在单独的范围{ ... } 中或在全局对象的析构函数中调用_CrtDumpMemoryLeaks 应该不会显示任何泄漏。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-26
          • 2014-04-12
          • 2010-11-25
          • 2010-10-28
          • 1970-01-01
          • 1970-01-01
          • 2015-11-14
          • 1970-01-01
          相关资源
          最近更新 更多