std::string 运算符+() 内存泄漏?

发布于 2024-12-02 10:19:15 字数 2037 浏览 0 评论 0原文

我很担心,因为我写了一个小应用程序,如果我相信 valgrind (我实际上做了什么),似乎存在内存泄漏:

==9321== 251 bytes in 7 blocks are definitely lost in loss record 1 of 1
==9321==    at 0x402569A: operator new(unsigned int) (vg_replace_malloc.c:255)
==9321==    by 0x40D3D05: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x40D4977: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x40D57AC: std::string::reserve(unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x40D5EE6: std::string::operator+=(char) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x804E113: xl2::TextParser::getNextLfLine() (TextParser.cpp:162)
==9321==    by 0x804BFD5: xl2::UsbTree::parseStringInfo(xl2::TextParser&, std::string&, std::string&) (UsbTree.cpp:362)
==9321==    by 0x804B881: xl2::UsbTree::parseDevicesFile(std::string) (UsbTree.cpp:204)
==9321==    by 0x804B34E: xl2::UsbTree::updateTree() (UsbTree.cpp:70)
==9321==    by 0x804E2E4: scan(std::string) (testUsbTree.cpp:75)
==9321==    by 0x804E6CC: executeCommand(std::string) (testUsbTree.cpp:132)
==9321==    by 0x804E8F6: hushLoop() (testUsbTree.cpp:153)

这是有问题的函数:

/**
 * Returns the next line separated by UNIX style LF
 * @return The next line separated by UNIX style LF
 */
std::string TextParser::getNextLfLine()
{
    std::string line;   // The builded line

    while(this->hasMoreToken())
    {
        line += this->m_pText[this->m_iTokenLocation++];

        // Check if we have just seen a CR/LF character
        if(this->m_pText[this->m_iTokenLocation - 1] == '\n')
            return line;
    }

    return line;
}

程序通过离开主函数正确终止(不调用退出())。

我只是不明白为什么会出现内存泄漏。因为我的字符串是在堆栈中复制的,并且当函数离开时原始字符串应该被清除,对吗?或者误差可能会更高?在顶层,我还将返回的值分配给一个局部变量,然后将其作为字段放入对象中(通过复制)...

所以我想知道泄漏是否来自标准库或 valgrind,这将是真正令人惊讶的!

强烈赞赏任何指向未泄漏内存的指针:-p!

I'm quite worry because I wrote a little application and it seems that there is a memory leak if I believe valgrind (What I actually do):

==9321== 251 bytes in 7 blocks are definitely lost in loss record 1 of 1
==9321==    at 0x402569A: operator new(unsigned int) (vg_replace_malloc.c:255)
==9321==    by 0x40D3D05: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x40D4977: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x40D57AC: std::string::reserve(unsigned int) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x40D5EE6: std::string::operator+=(char) (in /usr/lib/libstdc++.so.6.0.13)
==9321==    by 0x804E113: xl2::TextParser::getNextLfLine() (TextParser.cpp:162)
==9321==    by 0x804BFD5: xl2::UsbTree::parseStringInfo(xl2::TextParser&, std::string&, std::string&) (UsbTree.cpp:362)
==9321==    by 0x804B881: xl2::UsbTree::parseDevicesFile(std::string) (UsbTree.cpp:204)
==9321==    by 0x804B34E: xl2::UsbTree::updateTree() (UsbTree.cpp:70)
==9321==    by 0x804E2E4: scan(std::string) (testUsbTree.cpp:75)
==9321==    by 0x804E6CC: executeCommand(std::string) (testUsbTree.cpp:132)
==9321==    by 0x804E8F6: hushLoop() (testUsbTree.cpp:153)

Here is the function in question :

/**
 * Returns the next line separated by UNIX style LF
 * @return The next line separated by UNIX style LF
 */
std::string TextParser::getNextLfLine()
{
    std::string line;   // The builded line

    while(this->hasMoreToken())
    {
        line += this->m_pText[this->m_iTokenLocation++];

        // Check if we have just seen a CR/LF character
        if(this->m_pText[this->m_iTokenLocation - 1] == '\n')
            return line;
    }

    return line;
}

The programm terminates correctly by leaving the main funciton (no call to exit()).

I just don't understand why there is a memory leak. As my string is copied in the stack and the original string is supposed to be cleaned when the function is left, right? Or the error could be higher? At top level I also assign the returned value to a local variable that is then put as field into an object (by copy) ...

So I was wondering if the leak comes from the standard library or valgrind what would be really surprising!

Any pointers to not leaked memory is strongly appreciated :-p!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

全部不再 2024-12-09 10:19:15

引用Valgrind 常见问题解答

对于 GCC 2.91、2.95、3.0 和 3.1,使用带 -D__USE_MALLOC 的 STL 编译所有源代码。提防!从版本 3.3 开始,它已从 GCC 中删除。

对于 GCC 3.2.2 及更高版本,您应该在运行程序之前导出环境变量 GLIBCPP_FORCE_NEW。

在 GCC 3.4 及更高版本中,该变量已更名为 GLIBCXX_FORCE_NEW。

也在 GCC 常见问题解答中进行了讨论

To quote Valgrind FAQ

With GCC 2.91, 2.95, 3.0 and 3.1, compile all source using the STL with -D__USE_MALLOC. Beware! This was removed from GCC starting with version 3.3.

With GCC 3.2.2 and later, you should export the environment variable GLIBCPP_FORCE_NEW before running your program.

With GCC 3.4 and later, that variable has changed name to GLIBCXX_FORCE_NEW.

Also discussed in GCC FAQ

巴黎盛开的樱花 2024-12-09 10:19:15

我不会太担心 STL 泄漏。

默认的 STL 分配器(用于 gcc)使用巧妙的技巧来最大限度地提高效率,Valgrind 经常将其报告为泄漏。值得注意的是,它会池化内存,这意味着当您清除字符串时,它会保留内存,并且可以在下次插入map向量时重用它> 例如。

我不认为池本身在程序结束时被正确处置,可能是为了避免静态销毁顺序惨败(即,想象池被处置,然后您请求内存,urk)。因此,它会在程序结束并且操作系统强制收回内存之前泄漏。

I would not worry too much about STL leaks.

The default STL allocator (for gcc) uses clever tricks to maximize efficiency that Valgrind often reports as leaks. Notably it pools memory, meaning that it keeps memory around when you clear a string and may reuse it next time you insert in a map or a vector for example.

I don't think the pool itself is properly disposed of at the end of the program, probably to avoid the Static Destruction Order Fiasco (ie, imagine that the pool is disposed of and you then request memory, urk). Thus it leaks... right before your program ends and the OS gets the memory back forcefully.

日久见人心 2024-12-09 10:19:15

我怀疑编译器正在使用 NRVO 将临时字符串放入其真正的返回位置。然后,该返回字符串存储在已分配并从堆中泄漏的对象内。

I suspect what's happening is the compiler is using NRVO to put your temporary string into its real return location. That return string is then stored inside an object that's allocated and leaked off the heap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文