Will std::string delete the char buffer allocated via new? - c++

Is here a memory leak?:
#include <iostream>
#include <string>
class A{
std::string value;
public:
A(){
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
value = std::string(tmp);
}
std::string const& getValue() const {
return value;
}
};
int main(){
A a;
std::cout << a.getValue() << '\n';
}
since the value is constructed from pointer to newed memory, and thus the std::string is taking the ownership of it, will it also destroy? Or is it my responsibility to take care of that temporary object? And if so, the only way to destroying it is via having it as private variable, otherwise it goes out of scope (since the pointer is with auto storage created in constructor function).
So how is here the buffer managed?

The answer is no. I mean imagine if it did and you did this (ignoring the missing 0)
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
std::string value1 = std::string(tmp);
std::string value2 = std::string(tmp);
You would be very upset if the second string creation failed
Also std::string(const char*s) cannot tell that the memory for s is on the heap, stack or static. All it can see is a pointer. Even if it wanted to steal the memory it has no way of knowing if its doable

thus the std::string is taking the ownership of it
This assumption is incorrect. std::string doesn't take ownership of any pointer, constructor taking char* copies the data into internal storage. So yes, you have to delete[] what you new[]'ed.
Also, if you are passing char* to std::string, it must be null terminated:
A(){
char *tmp = new char[4];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
tmp[3] = '\0';
value = std::string(tmp);
}

And thus the std::string is taking the ownership of it, will it also destroy?
If you take ownership of a resource, that means that you will eventually release the resource (unless you transfer it to some other owner, and unless the ownership is shared). If you don't release the resource (or the mentioned exceptions apply), then either you have not taken ownership, or you have a bug.
std::string will only delete a buffer that std::string has created. std::string will not take ownership of a buffer that you have created. Your assumption of "std::string is taking the ownership" is wrong.
Never try to guess whether some function / constructor takes ownership or not. Always rely on documentation to find that out.
Or is it my responsibility to take care of that temporary object?
Yes. You are responsible for freeing the allocations that you create (until you transfer the onwership to something like a smart pointer).
The dynamic allocation that you created leaks, because you don't deallocate it.
And if so, the only way to destroying it is via having it as private variable, otherwise it goes out of scope
You can simply delete it after the std::string has been created and thus your buffer is no longer used.
Important! std::string constructor that accepts char* requires that the pointed string is null terminated. Your string doesn't contain the null terminator character, and thus the call violates the precondition. The behaviour of your program is undefined.
Furthermore, the allocation is entirely unnecessary. You can achieve the intended behaviour and fix both the undefined behaviour and the memory leak by writing the constructor like this:
A(): value("abc") {}
but what if I get the char pointer from another function that malloced it
Primarily, try to avoid calling such functions.
But in case you have no other option, then you must understand that the function is transferring the ownership of the allocation to you (I cannot think of any other reason the function would document that it used std::malloc). You must deallocate it using std::free once you no longer need it. Ideally, you should use something like a smart pointer to do so.
I used uuid_unparse which gives char pointer generated from malloc (see its documentation)
According to the documentation of uuid_unparse, it doesn't do such thing. It doesn't allocate anything. If you want to use it with std::string, you can do this:
uuid_t some_uuid = example_uuid();
constexpr std::size_t uuid_size = 36;
std::string str(uuid_size, '\0');
uuid_unparse(some_uuid, str.data());

The 5th constructor explained in the documentation takes the char* argument. It means it takes the pointer pointing the c-style string, calculates its length and then converts to std::string. The memory of original c-style char* string isn't released, so you have memory leak unless you later delete the char* string somewhere in code.

Most interesting comment:
#MarekR the point was, I tried to replicate the error I got. I used
uuid_unparse which gives char pointer generated from malloc (see its
documentation), but in class handling uuid I had std::string. And
since the std::string does not have ownership, I had to change the
implementation of the class to handle char pointers only –
milanHrabos
Apparently you are using uuid_unparse with c++ in wrong way and when problem appeared you asked question which do not reflect actual problem.
I would use this API in following way:
std::string uuid_to_string(uuid_t uu)
{
char buff[37];
uuid_unparse(uu, buff);
return buff; // implicit conversion to std::string is done here.
}
or more fancy way to do it:
std::string uuid_to_string(uuid_t uu)
{
std::string buff(size_t{36}, '\0');
uuid_unparse(uu, buff.data()); // since C++17 data returns `char *`
return buff;
}
About your code:
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
value = std::string(tmp);
this has 3 issues:
you are allocating memory which is not freed (string doesn't take over ownership of it) - so memory leak
your buffer do not contain terminating zero, so when it is passed to std::string this leads to undefined behavior since and of string can't be determined
code is simply over-complicated. After understudying what was its purpose I was able to provide simple solution.

Related

Is it safe to return a std::string by value?

In the following code, a string is encapsulated within a class, Foo.
The call to Foo::getText() returns the string by value. This creates a second instance of the string object, but both string objects now point to the same char buffer on the heap.
When the Foo instance is deleted, the the encapsulated string is automatically destructed, and therefore the char buffer on the heap is deleted.
Even though getText() returns a string by value, the resulting string object still relies on the lifetime of the original string object in order to retain the char buffer to which they mutually point.
Doesn't this mean that the printing of the retval to the terminal is an invalid access to memory that has already been free'd on the heap?
class Foo
{
Foo(const char* text) :
str(text)
{
}
std::string getText()
{
return str;
}
std::string str;
};
int main()
{
Foo pFoo = new Foo("text");
std::string retval = foo.getText();
delete pFoo;
cout << retval; // invalid memory access to char buffer?
}
I think a lot of people assume that, because the string was returned by value, they need not be concerned about the lifetime of the original string within Foo. This problem isn't strictly related to strings, but really applies to any class with encapsulated pointers that are free'd upon destruction. But what's the best practice here when it comes to strings?
Never return string by value?
Only return strings by value if the lifetime of the original string is guaranteed?
Always make a copy of the string? return std::string(retval.c_str());
Enforce a contract with the caller of getText()?
EDIT:
I think I was misled by RVO. All three strings in this example return a c_str at the same address. Is RVO to blame?
class Obj
{
public:
Obj() : s("text")
{
std::printf("%p\n", s.c_str());
}
std::string getText() { return s; }
std::string s;
};
int main()
{
Obj* pObj = new Obj();
std::string s1(pObj->getText());
std::string s2 = pObj->getText();
delete pObj;
std::printf("%p\n", s1.c_str());
std::printf("%p\n", s2.c_str());
}
Result:
0x600022888
0x600022888
0x600022888
This creates a second instance of the string object, but both string objects now point to the same char buffer on the heap.
No, they don't.
std::strings own their contents. When you copy a std::string, you copy its buffer.
I think a lot of people assume that, because the string was returned by value, they need not be concerned about the lifetime of the original string within Foo.
And those people are right. There is no "sharing".
Your return by value is fine and you needn't think more about it.
I'd like to add some points to #LightnessRacesInOrbit's answer:
Never return string by value?
Never return local strings by reference or pointer. Actually, never return anything local by reference or pointer. By value is just fine.
Only return strings by value if the lifetime of the original string is
guaranteed?
Again, you're thinking backwards. Only return by reference or pointer if the lifetime of the original is guaranteed.
Always make a copy of the string? return std::string(retval.c_str());
C++ does this automatically for you, if it can't move the string out (RVO/NRVO). No need to copy manually.
Enforce a contract with the caller of getText()?
Not needed as you get a copy anyway
I think a lot of people assume that, because the string was returned by value, they need not be concerned about the lifetime of the original string within Foo. This problem isn't strictly related to strings, but really applies to any class with encapsulated pointers that are free'd upon destruction.
And their assumption is correct. Any class with a (working) copy-constructor can be copied as often as needed and every copied instance is completely independent from the others. The copy-constructor takes care of copying the heap-space.

C++ / destructor - operator delete

I was wondering if I have to delete this pointer in example like this :
class Person
{
public:
Person(char *name) :_name(name) {}
// Is this delete necessary?
~Person() {
cout<<"Godbay Person"<<endl;
delete _name;
}
private:
char * _name;
}
This is pretty surely wrong in any case.
There are two possibilities:
The name is created on the free store exclusively for your object, and your object has to assume ownership. Then the name has to be deleted.
The name is not created on the free store (e.g. as a string litaral, which is quite possible), or some other object is managing the name, so your object should not assume ownership. Then any deletion would wreak havoc with your program.
So why do I say its wrong even in the first case? Because name sounds like a string, not a single character, wich means name* will point to an dynamically alocated array of characters. In that case, the correct way to delete it would be delete[] name.
But: If possible, avoid using plain (char) pointers, for case 1. Use some memory management class instead (a string class or smartpointers), to get rid of the headaches of manually managing memory ownership. delete and delete[] should appear only seldom in your code except if you don't have access to up-to-date C++ compilers.
It is a matter of who owns the allocated memory, in this case it looks like Person is not owning it so then no, so there is no need to delete. Using raw pointers like you do in Person always give rise to questions about ownership, that is why it is recommended to use shared_ptr/unique_ptr instead or even better std::string since it seems to be a string.
Generally, you have to call delete each time you create a pointer with new.
It depends on creation procedure.
In this case no:
Person *p = new Person("John");
In this case yes:
char *str = new char[32];
::strcpy(str, "John");
Person *p = new Person(str);
In this case yes, but with ::free function rather than operator delete.
char *str = (char *)::malloc(32);
::strcpy(str, "John");
Person *p = new Person(str);
Consider using std::string instead of C string pointer.

Deleting Strings on the Heap Created from Char[] one the Heap in C++

I have a fairly simple question that I cannot seem to find an answer for relating to C++ std::string and how it is instantiated with new. Now, I am well aware that any pointer returned from new should be subsequently deleted to prevent memory leak. My question comes from what happens when an existing pointer is subsequently used to instantiate a new string object. Please consider the following simplified example:
char* foo() {
char* ptr;
ptr = new char[ARBITRARY_VALUE];
...
ptr = strncpy("some null terminated string", ARBITRARY_VALUE)
...
return ptr;
}
int main() {
char* buf;
std::string myStr;
buf = foo();
myStr = new std::string(buf);
...do stuff
delete myStr;
delete buf; //Is this necessary?
return 0;
}
My question is simple: does deleting myStr also free the underlying memory used by buf or does buf need to be freed manually as well? If buf has to be freed manually, what happens in the case of anonymous parameters? As in:
myStr = new std::string(foo());
My suspicion is that the underlying implementation of std::string only maintains a pointer to the character buffer and, upon destruction, frees that pointer but I am not certain and my C++ is rusty at best.
Bonus question: How would this change if the class in question were something other than std::string? I assume that for any user created class, an explicit destructor must be provided by the implementer but what about the various other standard classes? Is it safe to assume that deletion of the parent object will always be sufficient to fully destruct an object (I try to pick my words carefully here; I know there are cases where it is desirable to not free the memory pointed to by an object, but that is beyond the scope of this question)?
std::string may be initialized from a C style null-terminated string (const char *). There is no way for std::string to know if you need that const char * free()d, delete[]()d or neither, and as already stated it won't.
Use smart-pointers to automatically delete dynamically allocated objects. There are a few different of these, each specialized for particular purposes. Have a look at scoped_ptr, auto_ptr and shared_ptr. Your project will probably have constraints on which smart pointers you get to use.
In the context of C++ there is never a reason to hold strings in manually declared char arrays, std::string is much safer to use.

How do I prevent deletion of a pointer returned by a member function?

Consider the sample code below. The class Data is used to store an array of data: for simplicity, I chose to use a vector<char> as data member. However, these data must be processed by an external routine, which requires a pointer to the first element of the array and, of course, the length of this array: for this reason, I have also implemented the functions get_data() and get_length().
class Data
{
public:
Data(const char* sourcePtr, int sourceLength) : _data(sourcePtr, sourcePtr+sourceLength) { ; }
const char* get_data() const { return &_data.front(); }
int get_length() const { return _data.size(); }
void print() const
{
vector<char>::const_iterator it;
for(it = _data.begin(); it != _data.end(); ++it)
cout << *it;
}
private:
vector<char> _data;
};
Now consider the following code sample, which uses the class Data.
int main(int argc, char** argv)
{
char* a = new char[4];
a[0] = 'b';
a[1] = 'y';
a[2] = 't';
a[3] = 'e';
Data myData(a,4);
delete[] a;
myData.print();
cout << endl;
const char* aPtr = myData.get_data();
// The following statement frees the memory allocated
// for the data member of the class Data.
delete[] aPtr;
return 0;
}
The above statement delete[] aPtr frees the memory allocated for the data member of the class Data. As a consequence, when the myData object is deallocated automatically, the content of the vector<char> has already been deallocated manually, and obviously an error SIGABRT occurs.
How to ensure that the compiler signals the statement delete[] aPtr as an error? How should you modify the class Data to achieve this goal?
The most straightforward way to deal with this is to make sure that it is clear who is the "owner" of a pointer. In my C++ days, if a pointer was returned by a function, the function's name should start with "Create" rather than "Get". Later, we usually returned smart pointers, in such a scenario.
It is in fact not at all hard to write C++ where you never need to delete any pointer explicitly, but rather store all of them in a smart pointer that will delete the pointee when it gets destroyed itself.
Stop using "naked" new and delete operations, wrap the new in an RAII type and do not use delete unless you're writing a destructor of an RAII type.
std::unique_ptr<char[]> a{ new char[4] };
a[0] = 'b';
a[1] = 'y';
a[2] = 't';
a[3] = 'e';
Data myData(std::move(a),4);
This code means that ownership of the array is clearly given to the smart pointer, and then clearly transferred to the Data object. Attempting to delete the array will not compile.
This doesn't prevent users later doing delete[] aPtr but if you get into the habit of never using delete except in the destructor of an RAII type, then it becomes glaringly obvious when someone introduces a bug by using delete somewhere they shouldn't, because they don't own the memory.
Stop fiddling about with bare pointers. If users of your code won't stop doing so then let them learn the hard way.
You don't. new and delete don't track who owns the pointer. That's your job.
What you can do instead is make a copy of the data the pointer points to. Then it doesn't matter what the caller does with its array. You have your own copy, and assuming you're not doing something braindead like exposing it to anyone who wants it, it's safe.
Or, check out std::unique_ptr and std::shared_ptr. :P They're the new hotness as far as memory management is concerned; when you use a smart pointer, memory very nearly manages itself.
Write good documentation. It's not your job to prevent other programmers from doing stupid things.

String literals inside functions: automatic variables or allocated in heap?

Are the string literals we use inside functions automatic variables? Or are they allocated in heap which we have to free manually?
I've a situation like the code shown below wherein I'm assigning a string literal to a private field of the class (marked as ONE in the code) and retrieving it much later in my program and using it (marked as TWO). Am I assigning a variable in the stack to a field in ONE? Can the code be referencing to a dangling pointer which in this case worked because the program was small enough?
I've compiled and ran it, it worked fine but I'm having a strange crash in my actual program where I'm assigning string literals to fields of the class like this and I suspect the case I mentioned above.
#include <iostream>
using namespace std;
class MemoryLeak
{
private:
char *s;
public:
MemoryLeak() {}
void store()
{
s = "Storing a string"; // ONE
}
char *retrieve()
{
return s;
}
};
int main()
{
MemoryLeak *obj = new MemoryLeak();
obj->store();
cout << obj->retrieve() << endl; // TWO
delete obj;
return 0;
}
Should I be declaring the variable "s" as a char array instead of a pointer? I'm planning to use std::string, but I'm just curious about this.
Any pointers or help is, as always, much appreciated :) Thanks.
String literals will be placed in the initialized data or text (code) segment of your binary by the compiler, rather than residing in (runtime allocated) memory or the stack. So you should be using a pointer, since you're going to be referencing the string literal that the compiler has already produced for you. Note that modifying this (which would require changing memory protection typically) will change all uses of this literal.
It is undefined behaviour to modify a string literal, and is most likely the cause of the crash in your program (ISO C++: 2.13.4/2). The standard allows for a conversion from a string literal to char* for backwards compatibility to C and you should only have that conversion in your code if you absolutely need it.
If you wish to treat the string literal as a constant, then you can change the type of your member to a const char *.
If your design requires that s can be modified, then I would recommend changing its type to std::string.
Thank you Cody and Richard.
I found the cause of the bug. It was because I was doing a delete on an object which was already delete'd. I was doing:
if (obj != NULL) delete obj;
I changed it to:
if (obj != NULL)
{
delete obj;
obj = NULL;
}
Learning C++ is definitely fun :)
Maybe the cause of the crash is that you did not 0-terminate the string?
Lets have a look at your options.
There are also a couple of things you should do:
/*
* Should initialize s to NULL or a valid string in constructor */
MemoryLeak()
{
store();
}
void store()
{
// This does not need to be freed because it is a string literal
// generated by the compiler.
s = "Storing a string"; // ONE
// Note this is allowed for backward compatibility but the string is
// really stored as a const char* and thus unmodifiable. If somebody
// retrieves this C-String and tries to change any of the contents the
// code could potentially crash as this is UNDEFINED Behavior.
// The following does need to be free'd.
// But given the type of s is char* this is more correct.
s = strdup("Storing a string");
// This makes a copy of the string on the heap.
// Because you allocated the memory it is modifiable by anybody
// retrieving it but you also need to explicitly de-allocate it
// with free()
}
What you are doing is using C-Strings. These should not be confused with C++ std::string. The C++ std::string is auto-initialized to the empty string. Any memory allocated is de-allocated correctly. It can easily be returned as both a modifiable and non modifiable version. It is also easy to manipulate (i.e. grow shrink change). If you grow a C-String you need to re-allocate memory and copy the string to the new memory etc (it is very time consuming an error prone).
To cope with dynamically allocating your object I would learn about smart pointers.
See this article for more details on smart pointers.
Smart Pointers or who owns you Baby
std::auto_ptr<MemoryLeak> obj(new MemoryLeak());
obj->store();
std::cout << obj->retrieve() << std::endl; // TWO
// No need to delete When object goes out of scope it auto deletes the memory.