【问题标题】:my program is leaking with resource owned by boost::shared_ptr我的程序正在泄漏 boost::shared_ptr 拥有的资源
【发布时间】:2011-04-16 23:45:17
【问题描述】:

我不明白为什么我的程序会泄漏,也许你能发现它。

typedef boost::shared_ptr < std::string >   StringPtr;
typedef std::pair < HWND, StringPtr >       WMapPair; 
typedef std::map  < HWND, StringPtr >       WindowMap;

// this callback populates the WindowMap (m_Windows) by adding a WMapPair each time
BOOL CALLBACK EnumWindowsCallback( HWND hWnd )
{
    // adds this window to the WindowMap, along with its title text

    BOOL        bRetVal         = FALSE;
    int         nTextLen        = 0;
    char*       sWindowText     = NULL;     

    if( ! ::IsWindow( hWnd ) )
        return FALSE;

    nTextLen = GetWindowTextLength( hWnd );
    if( ! nTextLen )
        return TRUE;

    sWindowText = new char[nTextLen + 1];
    if( sWindowText )
    {
        GetWindowTextA( hWnd, sWindowText, nTextLen );

        m_Windows.insert( WMapPair(hWnd, StringPtr(new std::string(sWindowText))) );

        delete [] sWindowText;

        sWindowText = NULL;
        bRetVal     = TRUE;
    }

    return bRetVal;
}

我的类包含这个 WindowMap 人口可以正常工作,但拆解似乎不能正常工作。类析构函数调用此函数来清除映射 - 这应该释放 shared_ptr,从而删除它们,对吗? :)

void EraseList()
{       
    m_Windows.clear();  
}

我很想知道我缺少什么 - 所有的 StringPtr 都在泄漏。

更新 重新评论“StringPtr(new std::string(sWindowText)))”在风格上是错误的,我做了如下建议的更改,但是内存泄漏仍然存在。

BOOL CALLBACK EnumWindowsCallback( HWND hWnd )
{
    // adds this window to the WindowMap, along with its title text

    BOOL        bRetVal         = FALSE;
    int         nTextLen        = 0;
    char*       sWindowText     = NULL;     
    StringPtr   strPtr;     

    if( ! ::IsWindow( hWnd ) )
        return FALSE;

    nTextLen = GetWindowTextLength( hWnd );
    if( ! nTextLen )
        return TRUE;

    sWindowText = new char[nTextLen + 1];
    if( sWindowText )
    {
        GetWindowTextA( hWnd, sWindowText, nTextLen );

        strPtr = StringPtr(new std::string(sWindowText));

        m_Windows.insert( WMapPair(hWnd, strPtr) );

        delete [] sWindowText;

        sWindowText = NULL;
        bRetVal     = TRUE;
    }

    return bRetVal;
}

结论 我已经接受了放弃 StringPtr 并使用 make_pair(hWnd, std::string()) 的建议,并以这种方式回避了这个问题。

【问题讨论】:

  • 这在风格上是错误的:StringPtr(new std::string(sWindowText))。每个新的动态分配对象最初都应该由一个 named 智能指针拥有。更多信息,请阅读the Boost shared_ptr best practices。另外,考虑使用std::vector&lt;char&gt; 而不是自己动态分配数组。不过,我认为这些都不是导致您的具体问题的原因。
  • @freefallr:不;当您有一个std::map&lt;int, std::string&gt; m; 并且您执行一个m.insert(std::make_pair(0, std::string("Hello World"))); 时,临时std::string("Hello World") 的副本将插入到std::map
  • 你确定你没有循环引用吗?这就是 boost::weak_ptr 的用途。
  • 您需要将向量调整为足够大,然后您可以使用&amp;v[0] 获取指向其初始元素的指针。例如:std::vector&lt;TCHAR&gt; v(nTextLen + 1); GetWindowText(hWnd, &amp;v[0], nTextLen);
  • @freefallr - 不,它不能! :-) 您链接到的页面是针对operator new 的,这是一个您可以覆盖的运算符,以便为某个类型分配一些特殊的内存。我的页面是关于new 的声明,例如new x。尽管他们都使用new这个词,但它们的含义不同。我可以向你保证new x 不会返回 NULL,它会抛出异常。

标签: c++ boost memory-leaks stdmap


【解决方案1】:

在 VS2010 std::vector&lt;&gt; 实现中存在(是?)一个错误,导致在某些情况下内存泄漏(请参阅 here)。 AFAIK,它已在 VS2010 SP1 中修复,但我不是 100% 肯定的。

【讨论】:

  • 感谢提醒,我不知道!我确实安装了 VS2010 SP1,我的问题似乎出在地图而不是矢量上。
  • 没有什么能阻止map 在内部使用vector
  • 我可以确认这已在 SP1 中修复。
【解决方案2】:

不打算回答你的问题(因为我看不到任何问题),但有几点:

typedef std::map  < HWND, std::string >     WindowMap;
typedef WindowMap::value_type               WMapPair;    // In the future it may not be a pair.
                                                         // Or you may change the type of WindowMap
                                                         // Make it so the value is based on the container.
                                                         // Done automatically.

// this callback populates the WindowMap (m_Windows) by adding a WMapPair each time
BOOL CALLBACK EnumWindowsCallback( HWND hWnd )
{
    // adds this window to the WindowMap, along with its title text

    // Declare variables at there first usage point.
    // There is no need to clutter the top of the function 
    // With usless variables that may never be used.

    if( ! ::IsWindow( hWnd ) )
        return FALSE;

    int nTextLen = GetWindowTextLength( hWnd );
    if( ! nTextLen )
        return TRUE;

    // Use a vector. Dynamically allocating memory is dangerious and not
    // exception safe (unless you use a smart pointer (or in this case a container))
    std::vector<char>  sWindowText(nTextLen + 1);
    GetWindowTextA( hWnd, &sWindowText[0], nTextLen );

    // No need for shared pointers. Just put the string in the map.
    m_Windows.insert( WMapPair(hWnd, std::string(sWindowText.begin(),
                                                 sWindowText.begin()+ nTextLen)));

    return TRUE;
}

【讨论】:

  • 是的,我采用了这种方法(例如前面提到的詹姆斯的建议)
【解决方案3】:

我同意詹姆斯的建议:

@freefallr:不;当你有一个 std::map m;然后你做了一个 m.insert(std::make_pair(0, std::string("Hello World")));,临时 std::string("Hello World") 的副本被插入到 std: :地图。 ——詹姆斯·麦克内利斯

【讨论】:

    猜你喜欢
    • 2014-11-20
    • 1970-01-01
    • 2011-06-19
    • 2014-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多