【问题标题】:pimpl idiom struct memory leakpimpl idiom struct 内存泄漏
【发布时间】:2011-03-17 15:01:11
【问题描述】:

我们在课堂上使用 pimpl 成语。 pimpl 结构在包含 pimpl 指针的类中声明,如下所示:

struct MyClassImpl;
friend struct MyClassImpl;
boost::scoped_ptr<MyClassImpl> m_Impl;

pimpl 的实现在一个名为 MyClassImpl.cpp 的单独文件中 例如:

    struct MyClass::MyClassImpl
        {
            QString m_Name;                             
            int m_Type;                                 
            double m_Frequency;                         
            int m_DefaultSize;                          
            QVariant m_DefaultValue;
                 boost::shared_ptr<SomeOtherClass> m_SomeOtherClass;                    

            ~MyClassImpl()
            {
            }
        };

在包含 pimpl 指针的类的构造函数中,我会在成员变量初始化列表中有类似

m_Impl(new MyClassImpl())

现在,我们在源代码中启用了内存泄漏检测,如下所示:

// Memory leaks detection in Visual Studio
#if defined (_WIN32) && defined (_DEBUG)
#   define _CRTDBG_MAP_ALLOC
#   include <crtdbg.h>
#   define new new(_NORMAL_BLOCK ,__FILE__, __LINE__) 
#endif

我发现当程序退出时,MyClassImpl() struct m_Impl(new MyClassImpl()) 会报告内存泄漏:

..\..\src\MyClass.cpp(29) : {290222} normal block at 0x0B9664E0, 48 bytes long.
 Data: <X l V         Y@> 58 1C 6C 03 56 00 00 00 00 00 00 00 00 00 59 40 

我不明白为什么,因为 m_Impl 是 boost::scoped_ptr 并且 QString、QVariant 和 shared_ptr 都是托管的。有什么想法吗?

【问题讨论】:

  • 您确定在调用 exit 之前调用了 MyClass 析构函数吗?
  • 如果您想获得有关泄漏的更好信息,请获取 Visual Leak Detector。
  • shared_ptr 可能是引用循环的一部分,并阻止内容被释放。如果没有SomeOtherClass tho 的定义,就无法判断。
  • 那个 QVariant 看起来像是我的罪魁祸首。里面有什么?
  • Sam:是的,我确定调用了 MyClass 析构函数

标签: qt boost memory-leaks pimpl-idiom


【解决方案1】:

它看起来应该可以工作..

我觉得奇怪的是泄漏的大小,只有 48 个字节。

我得出的结论是 MyClassImpl 结构已被释放,但其中的某些东西并未释放。如果整个结构泄漏,泄漏将比 48 字节大得多。

但是,我仍然找不到该代码的错误。

获取 Visual Leak Detector 以增强您的调试,它是免费的。

http://vld.codeplex.com/

【讨论】:

  • 抱歉,还没有,我在工作中遇到了一些其他问题,因此优先级较低。不过,一旦我进一步检查,我会更新。
【解决方案2】:

也许 MyClass 的实例在没有被正确删除的情况下被释放?例如,如果使用placement new 将它们分配到某个地方,则它们不会被报告为单独泄漏,但它们也不会在释放内存时自动销毁。

【讨论】:

  • 你能解释一下,没有被正确删除的释放是什么意思?我仔细检查了 MyClassImpl 的构造函数是否在包含类 MyClass 被破坏时被调用。是不是作用域指针还没有被破坏?
  • 我的意思是可以在一块原始内存中构造一个 MyClass 的实例——即,一个“void *”——使用一种称为“placement new”的特殊形式的 new。当该内存被释放时,其中的对象不会自动销毁。如果发生这种情况,包含 MyClass 实例的 void * 块不会泄露,但 MyClassImpl 会泄露。这只是一个理论——我敢肯定还有其他可能出错的事情。
猜你喜欢
  • 2015-01-30
  • 2013-03-08
  • 1970-01-01
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
相关资源
最近更新 更多