Skip to main content
gamedev.net
🔒 Locked

Curious memory issue with std::string

Started by King of Men Jul 31, 2007 at 10:24 PM 9 replies 10.9k views
Original Post
King of Men
King of Men
I am trying to remove all memory leaks from my program, using valgrind. The last one is a bit hard to understand, though. Here is the valgrind output:
1,024 bytes in 1 blocks are possibly lost in loss record 13 of 15
==10676==    at 0x4004C0F: operator new(unsigned) (vg_replace_malloc.c:163)
==10676==    by 0xB7B3F0: std::__default_alloc_template<true, 0>::_S_chunk_alloc(unsigned, int&) (in /usr/lib/libstdc++.so.5.0.3)
==10676==    by 0xB7B2FC: std::__default_alloc_template<true, 0>::_S_refill(unsigned) (in /usr/lib/libstdc++.so.5.0.3)
==10676==    by 0xB7AE6B: std::__default_alloc_template<true, 0>::allocate(unsigned) (in /usr/lib/libstdc++.so.5.0.3)
==10676==    by 0xB80E67: std::string::_Rep::_S_create(unsigned, std::allocator<char> const&) (in /usr/lib/libstdc++.so.5.0.3)
==10676==    by 0xB7D68C: std::string::_M_mutate(unsigned, unsigned, unsigned) (in /usr/lib/libstdc++.so.5.0.3)
==10676==    by 0xB819E2: std::string& std::string::_M_replace_safe<char const*>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, char const*, char const*) (in /usr/lib/libstdc++.so.5.0.3)
==10676==    by 0xB7E43B: std::string::operator=(char const*) (in /usr/lib/libstdc++.so.5.0.3)
==10676==    by 0x804A444: main (econsim.cc:35)

Now the code at econsim.cc:35 is a fairly innocuous assignment like so:
ost->name = "Ostlandet";
where the 'name' field is an std::string. Since it's not a pointer, it should surely just disappear when its owning object is deleted? I don't understand how this can be a memory leak; can someone more experienced with either valgrind or std::string give me a hand?
To win one hundred victories in one hundred battles is not the acme of skill. To subdue the enemy without fighting is the acme of skill.
Gorg
Gorg
Some STL implementations of string do not always release the memory it allocates to speed up future work by reusing the the allocated block.

The function _S_chunk_alloc, imho, is hinting at something like that.
Evil Steve
Evil Steve
I did a bit of sniffing around in the STL recently for my memory manager. Link
King of Men
King of Men
So you seem to be saying that I'll just have to live with this short of changing my STL implementation? I suppose I can, at that, it's just a kilobyte, but I had really hoped to clear valgrind of junk-output like this to make it easier to find serious stuff later on. [sad]
To win one hundred victories in one hundred battles is not the acme of skill. To subdue the enemy without fighting is the acme of skill.
Evil Steve
Evil Steve
Quote:
Original post by King of Men
So you seem to be saying that I'll just have to live with this short of changing my STL implementation? I suppose I can, at that, it's just a kilobyte, but I had really hoped to clear valgrind of junk-output like this to make it easier to find serious stuff later on. [sad]
Pretty much. Or you could write your own memory allocator (Which is fairly straightforward) for debug builds, and ignore STL allocations (Or do what I do, and ensure that the memory manager is destroyed after the STL internals).
wack
wack
Quote:
Original post by King of Men
So you seem to be saying that I'll just have to live with this short of changing my STL implementation? I suppose I can, at that, it's just a kilobyte, but I had really hoped to clear valgrind of junk-output like this to make it easier to find serious stuff later on. [sad]


If you want to rid Valgrind of junk output, just make a suppression file!. That's what they're for ;)
Zahlman
Zahlman
Or you could, you know, not write memory leaks in the first place, by not writing things in the kinds of ways that tend to create memory leaks. When I write stuff in C++, I never find myself wanting something to check up on the memory leaks for me, because I know I'm not "taking any risks".

This means: use standard library containers (for everything where they make sense, not just std::string), and RAII-ify your own classes - most easily, by creating (or using existing) RAII wrappers for those data members that might have a problem, and then just treating the wrappers like "ordinary" data members. (you can often just store a smart pointer to something, write member functions that delegate to the pointed-at thing, and never have to write an assignment operator, copy constructor or destructor.)
shukapi
shukapi
Zahlman, I think Gorg was saying that even in a perfectly good code with evenly matched allocations, std::string can leak, deliberately.

Can you check with breakpoints before all std::string operations and prove that it's std::string's fault? Or would that take too long.

I've had corruption problems with std::string that are definitely the fault of std - modifying by taking the address of characters, taking copies, then modifying the characters - the copies get modified too - so std::string isn't perfect.
Emmanuel Deloget
Emmanuel Deloget
Quote:
Original post by shukapi
Zahlman, I think Gorg was saying that even in a perfectly good code with evenly matched allocations, std::string can leak, deliberately.

Can you check with breakpoints before all std::string operations and prove that it's std::string's fault? Or would that take too long.

I've had corruption problems with std::string that are definitely the fault of std - modifying by taking the address of characters, taking copies, then modifying the characters - the copies get modified too - so std::string isn't perfect.

That's a misconception: the library is NOT the definition; std::string is not perfect, yes, but its definition forbids such thing to happen, so it's not the fault of std::string: it's the fault of the implementation you use - and that's really not the same thing. Problems in std::string are design concerns; they can't be implementation issues.

And now that I reread what you've written, it seems to me that you did something veyr bad - something you don't have the right to do. You don't have the right to modify the characters in a string using their address. std::string makes quite clear that the data buffer and the textual representation of the string may be something different (that's why you have .c_str() and .data(), which both returns a const char_type*; c_str() guarantees that the returned string will be zero-terminated; data() makes no such guarantee. The standard doesn't mandate any particular form of storage, so both data() and c_str() return value may NOT fit the underlying representation of a string).
Zahlman
Zahlman
Quote:
Original post by shukapi
Zahlman, I think Gorg was saying that even in a perfectly good code with evenly matched allocations, std::string can leak, deliberately.


I understood him perfectly well, thank you. What I was saying is that if you write code that can be "easily seen not to have any memory leaks", you can stop worrying about it and not waste your time trying to set up leak detectors and memory managers. (Not to mention the difficulty of detecting the deallocation of globals.)

Quote:
I've had corruption problems with std::string that are definitely the fault of std - modifying by taking the address of characters, taking copies, then modifying the characters - the copies get modified too - so std::string isn't perfect.


Show an example?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.