std::string operator+() memory leak?

2019-03-24 18:10发布

问题:

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!

回答1:

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



回答2:

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.



回答3:

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.