This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
delete heap after returning pointer
I have a class with a member function:
char* toChar();
The member function allocates memory and return a pointer to that memory ...
lets say I would use it like this:
int main() {
MyClass mc = new MyClass();
char* str = mc.toChar();
return 0;
}
where should I free the memory? In the Destructor of the class or in the program like this:
int main() {
MyClass * mc = new MyClass();
char* str = mc.toChar();
// tostuff with str
delete mc;
delete[] str;
return 0;
}
If you want it to be reusable (that is, you can call it multiple times and it may return different values, maybe because the class has changed), then you should free it in the main. Otherwise it's up to you.
But in general you should NOT use plain strings. You should change it to use std::string and then return that by value.
The member function should return an object that manages the memory. Typically that would be std::unique_ptr, but for char data std::string may be more appropriate:
class MyClass {
...
std::string toChar();
};
int main() {
MyClass mc;
std::string str = mc.toChar();
}
Note that by also making mc a managed object (here it is managed directly on the stack; unique_ptr would also work but would be largely unnecessary) there is no need for delete to appear anywhere in your code. In general, unless you are writing your own containers, delete should not appear in your code.
The question is who is the "owner" of that piece of memory pointed by str. As mc returns a char* instead of a const char*, it allows the client (str) to modify the value of the string, so I would say str should also consequently take care of freeing the memory. What would happen if mc frees the memory but str still want to access it? The process will be terminated.
Related
EDIT: Sorry everyone, I don't think this toy example really reflected my problem. What I should have asked is if there is a way to release a std::string object's buffer. There is not, and that makes sense. Thanks!
Suppose I have the following (broken) code:
void get_some_data(MyCustomContainer& val)
{
std::string mystr = some_function();
val.m_data = &mystr[0];
}
This won't work, because the memory pointed by mystr is freed at the end of get_some_data, and the memory referenced by val.m_data will be invalid.
How can I tell a std::string "Don't free your memory buffer at your destructor!" ? I don't want to copy the data. The MyCustomerContainer object will handle the memory free-ing at its destructor.
You cannot do this without breaking the rules. The std::string class is not allowed to release its ownership explicitly. In fact, a std::string might not even have any memory allocated due to SBO optimization:
std::string str1 = "not allocating";
std::string str2 = "allocating on the heap, the string is too large";
This behavior is completely platform- and implementation-dependent. If a string doesn't allocate its buffer on the heap, the data is placed on the stack, which doesn't need de-allocation.
{
std::string str1 = "not allocating";
} // no buffer freed
So even if there were a way to tell the string not to de-allocate its buffer, there is no way to tell if the buffer is managed on the heap or not.
Even if there were a way to tell if the string uses the stack, you'd have to allocate a buffer in place as a class member and copy its content.
The idea of transferring a string's data and stealing its ownership over that string's memory resource is fundamentally broken as you can't get away without copying, simply because there might be no ownership to steal.
What I recommend is for you to copy the string content in all cases if you don't want to change how MyCustomContainer works:
void get_some_data(MyCustomContainer& val)
{
std::string mystr = some_function();
val.m_data = new char[mystr.size()];
std::memcpy(val.m_data, mystr.data(), mystr.size());
}
In contrast, if you allow MyCustomContainer to store a std::string, you could actually get away without copying when a buffer is allocated by moving the string:
void get_some_data(MyCustomContainer& val)
{
// let m_data be a std::string
val.m_data = some_function();
// The above is equivalent to this:
// std::string mystr = some_function();
// val.m_data = std::move(mystr);
}
Moving a string will invoke move assignation. With move assignation, the string implementation will transfer the ownership of the mystr's buffer into m_data. This will prevent any additional allocation.
If mystr didn't allocate, then the move assignment will simply copy the data (so no allocation there, either).
The right way to fix this problem is:
class MyCustomContainer {
public:
std::string m_data;
};
void get_some_data(MyCustomContainer& val) {
val.m_data = some_function();
}
The get_some_data could even be made into a member function, which would make the usage even easier at the callsite, and perhaps allow m_data to be private instead of exposed.
If .m_data is an std::string you can take advantage of std::string's move-assignment operator:
val.m_data = std::move(mystr);
If m_data is not an std::string you are pretty much out of luck, the internal buffer is inaccessible (as it should be).
No, you cannot. std containers will only give up their managed memory (and then only sometimes) to std containers of the same type.
For string this would be impossible regardless, as most implementations do a short string optimization and store short strings internally.
You could throw the std string into a global buffer somewhere and reap it at cleanup, but that gets insanely complex.
If you want you can use this code that causes Undefined Behavior, so it should not be used, but if you are working on some toy project of your own that will be quickly abandoned you can see if it works for you.
// REQUIRES: str is long enough so that it is using heap,
// std::string implementation does not use CoW implementation...
// ...
char* steal_memory(string&& str){
alignas(string) char buff[sizeof(string)];
char* stolen_memory = const_cast<char*>(str.data());
new(buff) string(move(str));
return stolen_memory;
}
If you want to handle short string you should add malloc and copy from buffer for that case.
Main idea here is to use placement new that takes the ownership from our input string, and not calling the destructor on string in buff. No destructor means no calls to free, so we can steal memory from the string.
Unfortunately const_cast is UB in this case so like I said you should never use this code in serious code.
You can do mystr static
void get_some_data(MyCustomContainer& val)
{
static std::string mystr;
mystr = some_function();
val.m_data = &mystr[0];
}
but, in this way, you have only one mystr for all get_some_data() calls; so
get_some_data(mcc1);
get_some_data(mcc2);
// now both `mcc1.m_data` and `mcc2.m_data` point to the same value,
// obtained from the second `some_function()` call
If you can compile-time enumerate the calls to get_some_data(), you can differentiate your mystr using a template index
template <std::size_t>
void get_some_data(MyCustomContainer& val)
{
static std::string mystr;
mystr = some_function();
val.m_data = &mystr[0];
}
get_some_data<0U>(mcc1);
get_some_data<1U>(mcc2);
// now `mcc1.m_data` and `mcc2.m_data` point to different values
I am trying to print out value 123456, but it gives me the garbage value. How can I fix it? And Can you please explain why it gives the wrong value?
#include <stdio.h>
#include <stdlib.h>
struct MyInfo
{
private:
int private_key = 123456;
public:
int setkey(int value)
{
private_key = value;
}
int GetScore()
{
return private_key;
}
};
void main()
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo));
printf("%d\n", pMyInfo->GetScore());
free(pMyInfo);
}
Don't use malloc/free but rather pMyInfo = new MyInfo() and delete pMyInfo. Only new will call the constructor which initializes the value; only delete will call the destructor.
Regarding the comment, what is meant is, you can also have it on the stack, i.e. MyInfo pMyInfo;, i.e. not a pointer. That will automatically call the constructor and when it goes out of scope, the destructor.
int private_key = 123456;
This really is just a camouflaged constructor initialization which means it's the same as:
MyInfo() : private_key(123456) {}
Since malloc and friends are inherited from C and C has no classes (and thus no special member functions) whatsoever malloc and friends won't call these necessary special member functions to set up your object. The C++ equivalent new does however which is why you should always use new over malloc and delete over free.
But wait, there's more...
Actually, you shouldn't ever use new either, there are always better alternatives than using raw dynamic allocation. If you really need dynamic memory allocation then use std::unique_ptr or for multiple objects std::vector but most of the time you don't even need these ( there are tons of posts on here that explain when dynamic allocation is a must, for all the other cases just use storage with automatic lifetime) all you need in this case is a local object:
MyInfo myInfo;
printf("%d\n", myInfo.GetScore());
See how your code just got shorter, easier to maintain and cleaner to achieve the same?
When you declare a pointer of type MyInfo, it does not mean that the object it points to will actually be your struct, it just assumes it will be.
When you do malloc(sizeof(MyInfo)), you simply allocate memory of the size which your struct might take, it does not create an object. Hence, when you try to do GetScore(), it accesses memory location which it assumes contains your private_key, but instead it simply contains garbage.
Don't mix C and C++
You should avoid malloc/alloc etc in C++ and opt for new operator if you want to work with dynamically allocated objects.
Add a constructor to initialize the value
private;
int private_key;
public:
MyInfo () {
private_key = 123456;
}
And implement the main like
// without pointer
void main () {
MyInfo myinfo;
printf("%d\n", myinfo.GetScore());
}
// with pointer
void main () {
MyInfo *myinfo = new MyInfo();
printf("%d\n", myinfo->GetScore());
}
Just for reference, it is possible to initialize an object in raw storage, but it would be overkill and rather stupid for this use case. As malloc only allocate raw memory and does not construct an object, you could use a placement new to build the object in a second time:
int main() // I can't stand void main
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo)); // only allocate raw memory
new((void *) pMyInfo) MyInfo; // construct the object
std::cout << pMyInfo->GetScore() << std::endl; // no reason for C printf here
pMyInfo->~MyInfo(); // placement new requires explicit destructor call if not trivial
free(pMyInfo);
return 0;
}
DO NOT DO THAT for such a simple case. Placement new should only be used in very special cases where the allocation is not trivial, for example when you use share memory. But here the correct way is to simply use an automatic object:
int main() // I can't stand void main
{
MyInfo pMyInfo;
std::cout << pMyInfo.GetScore() << std::endl;
return 0;
}
I have a problem.
The compiler keeps warning me for invalid use of the constructor.
All i wanted to do is to create a new course in the class. whats wrong?
int StArray::addCS_Course(int id, int CourseNum, char* CourseName,int HwNum, float HwWeigh, bool Takef, char* BookName){
int i;
CS_Course* course;
if ((CourseNum<0)||(HwNum<0)||(HwWeigh<0)||(HwWeigh>1))
return 0;
for (i=0;i<StudentNum_;i++){
if (Arr_[i]->getID()==id) {
course=(CS_Course*)malloc(sizeof(CS_Course*));
if (course==NULL) {
fprintf(stderr,"Malloc failed\n");
exit(0);
}
course->CS_Course::CS_Course(CourseNum,CourseName,HwNum,HwWeigh,Takef, BookName);
if (Arr_[i]->addCS_Course(course)==1)
return 1;
else
{
free(course);
return 0;
}
}
}
return 0;
}
To create a new object in C++, you don't do this:
course = (CS_Course*) malloc(...);
course->CS_Course::CS_Course(...);
you do this:
course = new CS_Course(...);
That code looks after both allocating memory and calling the constructor.
You then delete your object with delete course; rather than free(course);
(But as juanchopanza points out in the comments, it's considered bad form to create objects on the heap in C style like this - you should prefer to use standard library containers and avoid the use of new. That's a whole nother discussion - you might want to read a tutorial on modern C++.)
Edit by #RemyLebeau: If you need to construct an object in existing memory, use placement new instead:
buffer = malloc(...);
course = new (buffer) CS_Course(...);
But then you have to call the destructor manually:
course->~CS_Course();
free(buffer);
malloc(sizeof(CS_Course*)) allocates enough space for a pointer to a CS_Course, not a CS_Course itself. If malloc were the right way to dynamically allocate memory for an object, you would need to call it like this:
malloc(sizeof(CS_Course));
However, malloc isn't the right way to do this; in C++, you use new to dynamically allocate memory for objects:
course = new CS_Course; //Use the default constructor
or
//Use constructor with 2 parameters
course = new CS_Course(constructor_param1, constructor_param2);
Of course, if you don't need a pointer, you can (and should) create a CS_Course object like this (generally referred to as allocating on the stack):
CS_Course course; //default constructor
//constructor with 2 parameters
CS_Course course2(constructor_param1, constructor_param2);
I have a class that holds a few vectors, I'm not sure which method is the best but when the I call the destructor they should be deleted from memory.
HEADER:
class Test
{
public:
Test();
~Test();
void AddString(char* text);
void AddString(string text);
private:
char * StringToCharPointer(string value);
vector<char*> *pVector;
}
CPP File:
Test::Test()
{
};
Test::~Test()
{
vector<char*>::iterator i;
for ( i = pVector->begin() ; i < pVector->end(); i++ )
{
delete * i;
}
delete pVector;
};
char * Test::StringToCharPointer(string value)
{
char *pChar = new char[value.length()];
strcpy(pChar, value.c_str());
return pChar;
};
Test::AddString(char* text)
{
pVector->push_back(text);
};
Test::AddString(string text)
{
pVector->push_back(StringToCharPointer(text));
};
so here's pretty much all the methods that I use, but what's wrong?
Firstly, i is an iterator on the vector, it is not the pointer stored in the vector. *i is the pointer stored in the vector, so if you're going to delete anything it should be that.
Secondly, delete *i is only valid if the object pointed to by *i was allocated with new. Not new[], not malloc, and it doesn't point to a string literal. Since you don't say how your data was allocated, it is not possible for us to say whether or not you are freeing it correctly.
It seems likely that you should use a std::vector<std::string>.
Update for updated question:
HEADER:
class Test
{
public:
Test();
~Test();
void AddString(const string &text);
private:
vector<string> mVector;
};
CPP file:
Test::Test()
{
};
Test::~Test()
{
};
void Test::AddString(const string &text)
{
mVector.push_back(text);
};
Your destruction code looks fine (although I guess you meant delete *i; in the second snippet, since otherwise, ti wouldn't have even compiled.
However, the errors you are getting indicate you put bad things in your vectors. The only char*s that can be inserted in the vector with such destruction code are the ones returned by new char. Especially, you must not insert literals ("abc") or strings that are made as parts of other strings (strtok(NULL, ":"), strchr(str, ':') into it.
This is one obvious problem: char *pChar = new char[value.length()];. You are doing new[] but doing delete in destructor which invoked undefined behavior. You should use delete[] to delete those pointers. But using delete[] might give problems for Test::AddString(char* text) method as you can not be sure how memory for text is allocated i.e. using new or new[] or malloc. The simplest way is to use std::vector<std::string> as suggested by Steve Jossep.
It seems likely that you should use a std::vector<std::string>, to shorten the wise words of Steve Jessop.
To elaborate a little more: you say you want "to make the memory allocation smaller", but sounds like you're at the wrong path if you don't know pointers, and correct me if I'm wrong in guessing premature optimization (usually the case with inexperienced developers in this type of question).
What's the best way to delete an std::string from memory allocated on the heap when I'm done using it? Thanks!
std::string is just a normal class1, so the usual rules apply.
If you allocate std::string objects on the stack, as globals, as class members, ... you don't need to do anything special, when they go out of scope their destructor is called, and it takes care of freeing the memory used for the string automatically.
int MyUselessFunction()
{
std::string mystring="Just a string.";
// ...
return 42;
// no need to do anything, mystring goes out of scope and everything is cleaned up automatically
}
The only case where you have to do something is when you allocate an std::string on the heap using the new operator; in that case, as with any object allocated with new, you have to call delete to free it.
int MyUselessFunction()
{
// for some reason you feel the need to allocate that string on the heap
std::string * mystring= new std::string("Just a string.");
// ...
// deallocate it - notice that in the real world you'd use a smart pointer
delete mystring;
return 42;
}
As implied in the example, in general it's pointless to allocate a std::string on the heap, and, when you need that, still you should encapsulate such pointer in a smart pointer to avoid even risking memory leaks (in case of exceptions, multiple return paths, ...).
Actually std::string is defined as
namespace std
{
typedef std::basic_string<char> string;
};
so it's a synonym for the instantiation of the basic_string template class for characters of type char (this doesn't change anything in the answer, but on SO you must be pedantic even on newbie questions).
std::string foo("since it's on the stack, it will auto delete out of scope");
or:
std::string* foo = new std::string("allocated on the heap needs explicit destruction")
delete foo;
Use delete if it's on the heap, and nothing at all if it's on the stack.
void foo() {
string* myString = new string("heap-allocated objects are deleted on 'delete myString;'");
cout << *myString << endl;
delete myString;
}
or better yet, avoid pointers when possible and use automatic variables:
void foo() {
string myString("stack-allocated string is automatically deleted when myString goes out of scope");
cout << myString << endl;
}
just treat std::string as any basic type.
std::string *str = new std::string("whatever");
///code
delete str;
Maybe your dealing with really freeing the internal string buffer?
For performance reason, most implementation keep the internal buffer allocated, even is the string is "emptied". Additionally: small strings (smaller than sizeof(ptr)) are directly stored in the area that hold pointers. Theses bytes can never be reclaimed during the life of the string.
To free the internals: the classical trick is to use swap within a scope. This force buffer to be really freed (Works also with vector/map/ostream/stringstream etc ...):
string s; // size==0 and capacity==15 as the default proxy of the container (help perf on small string)
s = "Looooooooooooooooooooooooooooooong String"; // size==41 and capacity==47 bytes allocated
s.clear(); // size==0 BUT capacity==47 bytes STILL allocated!!
s = "Looooooooooooooooooooooooooooooong String"; // size==41 and capacity reuse 47 bytes still allocated.
s.resize(0); // size==0 BUT capacity==47 bytes STILL allocated!!
// swap with scope to force freeing string internals
{
string o;
o.swap(s);
} // size==0 AND capacity==15 (back to smallest footprint possible)
s = "12345"; // size==5 AND capacity==15 (the string is IN the container, no new alloc)
You can treat std::string like any other class. Use new for allocation, and delete once you're done with it.
With C++11, I do not recommend usage of new and delete in most cases. If you need to allocate the string on heap, use std::shared_ptr to wrap it:
std::shared_ptr<std::string> my_string = std::make_shared<std::string>(std::string("My string"));
As soon as all the copies of my_string go out of scope, the associated memory is going to be deleted automatically.