0

Recently i have the problem with c_str().below is the sample code snippet

#include<bits/stdc++.h>
#include<unistd.h>
using namespace std;
class har{

    public:
    string h;
    har(string str){
        h=str;
    }
};

int main(){


har *hg=new har("harish");
const char *ptr=hg->h.c_str();
delete hg;
cout<<ptr<<endl;
return 0;
}

I am getting the output as "harish"....I have destroyed the object but still i am getting the output..is c_str() again allocating memory in heap.

v.ladynev
  • 19,275
  • 8
  • 46
  • 67
  • Accessing deleted objects is undefined behaviour. And no, `c_str()` simply returns a pointer to the string. – Jabberwocky Oct 03 '18 at 13:37
  • 1
    Also, see [Why should I not #include ?](https://stackoverflow.com/q/31816095/580083) – Daniel Langr Oct 03 '18 at 13:40
  • Not related to your question, but the dual combo of [`bits/stdc++.h`](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) and [`using namespace std;`](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) is a bad idea. – StoryTeller - Unslander Monica Oct 03 '18 at 13:42
  • calling delete is meant to tell the os that the specific memory area is free for reuse, not that the whole of it is completely zero'ed out right after that. you'll see this clearer and more often in programs run with repeated uses of dynamic alloc and dealloc functions. So only after main or when the objects in use become out of scope, will you be able to enjoy the non-allocated assets. – The Unknown Oct 03 '18 at 13:44
  • 1
    If you compile this with MSVC in DEBUG mode then your program will print garbage as MSVC is kind enough to fill deallocated memory with garbage when it frees it: http://rextester.com/HJYZ85336 – Paul Sanders Oct 03 '18 at 13:59

1 Answers1

7

c_str() gives you a pointer to the data buffer in std::string (with a NUL terminator guaranteed to be added at the end of the string), that's all. Note that the pointer is invalidated if the std::string goes out of scope, is destroyed, or is changed.

In your case the behaviour of cout << ptr << endl; is undefined. This is because ptr was set to the return value of c_str() on a string that no longer exists, and cout for const char* has a special overload that attempts to read the character buffer from that pointer up to the first NUL character encountered. The result you observe is a manifestation of that undefined behaviour.

Note that, cout << (void*)ptr << endl; is also undefined, as once you no longer own memory at an address, the pointer is essentially in an uninitialised state.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • Moreover, one should not even attempt to modify the returned string. – Eugene Sh. Oct 03 '18 at 13:39
  • @FrançoisAndrieux: Yup, the original draft had completely the wrong flavour to it. I've amended. – Bathsheba Oct 03 '18 at 13:43
  • we are deleting the object means we are destroying its memory in heap right...why still i am getting the output..can you guys please explain me in little detail as i am new to c++. – harish Dubakula Oct 03 '18 at 13:44
  • @harishDubakula: The result you observe is a manifestation of that undefined behaviour. – Bathsheba Oct 03 '18 at 13:45
  • 2
    Is using the value of `ptr` itself really ok? Isn't the pointer invalid after being freed due to destruction of the owning `std::string`? – Deduplicator Oct 03 '18 at 13:46
  • @Deduplicator; I'm checking, frantically. This is a tricky corner of the standard. – Bathsheba Oct 03 '18 at 13:47
  • @Deduplicator: You're correct, same as an uninitialised pointer read. – Bathsheba Oct 03 '18 at 13:48
  • @harishDubakula `std::string` buffer can live both on the heap and the stack (for small lengths, see SSO). This is irrelevant to your problem as explained by @Bathsheba. – Dan M. Oct 03 '18 at 13:48
  • will that memory of c_str() allocated in heap? – harish Dubakula Oct 03 '18 at 13:49
  • @Bathsheba `ptr` is a copy of the result of `c_str()`. It's definitely invalidated, but it shouldn't be modified by the destruction of the string. However, I'm also not 100% sure you are allowed to take address value of a pointer to a deleted object in general. For example, you can't read the address from a pointer you `delete` (see [this answer](https://stackoverflow.com/q/43508771/7359094)). This doesn't necessarily mean that this example applies to copies of such pointers, but I seem to remember taking the address from a pointer to a deleted object is just UB in general. – François Andrieux Oct 03 '18 at 13:49
  • @harishDubakula: It is free, but why would the C++ runtime clean up the memory? That would be a bit like cleaning the holiday cottage yourself before you left. – Bathsheba Oct 03 '18 at 13:49
  • @Bathsheba afaik you can cast it to `uintptr_t` and print that without any UB. No one forbids taking integer values of pointers, even if they don't point anywhere useful. – Dan M. Oct 03 '18 at 13:50
  • @DanM.: Yes, that's my understanding too, although I never program at such a level, so the rules are a little fuzzy in my head. – Bathsheba Oct 03 '18 at 13:50
  • can above code cause memory leak? – harish Dubakula Oct 03 '18 at 13:59
  • 1
    @harishDubakula It's UB, so yes, not that it matters. – Deduplicator Oct 03 '18 at 14:44