0

My question is about the following simple code:

#include <iostream>

using namespace std;

const char* call()
{
    string str("Hey there.");
    return str.c_str();
}

int main()
{
    const char* blah = call();
    cout << blah << endl;

    system("pause");
    return 0;
}

Output: "Hey there."

Now, how is it that the memory holding "Hey there." isn't destroyed or causing a memory leak when std::string is destroyed at the end of the method? I'm not a c++ expert but i believe if the string allocated memory holding "Hey there." on the stack, it would be deleted when the string goes out of scope (end of method), and if the string allocated memory on the heap to store "Hey there." then this would cause a memory leak since its clearly not destroying the memory because we are accessing the memory after the string has gone out of scope.

So, how is it that i am able to access the memory blocks pointed to by c_str() without causing a memory leak?

Thank you and much appreciated responses.

shawn a
  • 799
  • 3
  • 13
  • 21
  • 5
    Dumb luck. The memory location you were using haven't been reused yet. – user4581301 Jul 12 '15 at 01:03
  • 1
    @user4581301: actually, I do consider it _unlucky_ that it worked! Ideally the run-time system would fail on incorrect code. One way to do so in a test environment is to make pages with deleted memory inaccessible. Of course, that would yield a slow system but probably reveal quite a few errors of accessing stale data. An alternative could be to fill the memory with some pattern before releasing in the destructor of the class. – Dietmar Kühl Jul 12 '15 at 01:14
  • It was run on a Linux CentOS system if you were curious. – shawn a Jul 12 '15 at 01:18
  • 1
    The memory containing the string literal `"Hey there"` is *never* deallocated. It wasn't allocated in the first place. It is compiled into the constant data section. Not a duplicate @KerrekSB – user207421 Jul 12 '15 at 01:24
  • @EJP Ah that's very interesting i didn't know about a constant data section for string literals. Thanks! – shawn a Jul 12 '15 at 01:26
  • 4
    @EJP: it is a duplicate: the string literal is used to initialize the internal memory of `str` to which `c_str()` obtains a pointer. If the function has used `return "Hey there";` there would be no problem. The internal memory of `str` is release and accessed after the release. – Dietmar Kühl Jul 12 '15 at 01:27
  • @DietmarKühl I should have worded that better, though I suppose for some there is no greater joy than the adventure of having having software that works at the whim of the gods. – user4581301 Jul 12 '15 at 01:35
  • @EJP - wouldn't the `std::string` have _copied_ the string from that constant data section into its own memory area? So, while `"Hey there."` is certainly still in constant memory, `str.c_str()` is pointing not to that constant memory but to a copy of it somewhere else. (Unless `std::string` supports copy-on-write semantics for constant strings.) – celticminstrel Jul 12 '15 at 02:15

1 Answers1

1

I believe your string is technically out of scope but it does not get 'deleted' from memory immediately. It needs to get overwritten. When a variable goes out of scope, the machine does not guarantee it will still be valid, but by chance, it could. When you de-reference a pointer, there's a chance that the old string information is still there in that location in memory. Also the term 'memory leak' is reserved only for dynamic allocation of memory using the keyword new for when you lose the last pointer to that data which means you have lost access to that data.

Fuad
  • 1,419
  • 1
  • 16
  • 31
  • Thanks for the answer! I was referring to dynamic allocation using the keyword new. As in, the std::string object stores the char array "Hey there." via creating memory on the heap. Heap = dynamic allocation = new. – shawn a Jul 12 '15 at 01:08
  • @shawna: All those equal signs are wild, unwarranted assumptions. `std::string` doesn't use `new`; it uses the provided allocator. – Kerrek SB Jul 12 '15 at 01:11
  • @KerrekSB Heap = dynamic allocation = new, is a basic computing fact. No assumptions have been made. I didn't know how or where std::string stored its memory for its characters, thats why you see me saying "if" a lot in the original post. – shawn a Jul 12 '15 at 01:22
  • @shawna Not fact. One could override `new` with a function that returned an object from a static pool of objects. This happens quite often in embedded systems where you need to keep memory fragmentation under control. – user4581301 Jul 12 '15 at 01:43
  • @user4581301 Let's not bring up specific use-cases for the new operator and keep the discussion in the context of the question asked. – shawn a Jul 12 '15 at 01:47
  • @KerrekSB - While that's technically true, the _default_ allocator generally uses `new`, right? So the assumptions are not _entirely_ unwarranted. – celticminstrel Jul 12 '15 at 02:17
  • @celticminstrel: the default allocator uses `::operator new`, which is not entirely the same as, say, `new char[N]`, which I suspect the OP has in mind (and indeed *every* high-school my-first-string-class code seems to use). – Kerrek SB Jul 12 '15 at 11:11