Is the following C++ code a memory leak?
list.push_back(new String("hi"));
As I understand it, push_back from any std collection/container always makes a copy. So if the new string is copied, nothing can ever delete the new'd string right? since there is no reference to it after the push_back...
Am I correct or wrong here?
Thanks.
Jbu
edit: I think I am wrong, since new will return a pointer...we'll always have the pointer to be able to delete the new String
Yes, but not for the reason you think.
Depending on how list is defined and initialized, push_back might throw an exception. If it does, the pointer returned from new is lost, and can never be freed.
But assuming push_back returns successfully, it stores a copy of the pointer returned by new, and so we can free the memory later by calling delete on that copy, so no memory is leaked as long as you do call delete properly.
No, the vector stores pointers and the copy is made of the pointer. You can delete the object any time later.
(You may get a leak, if the statement happens to throw an exception and you don't catch and handle it properly. That's why you might consider using smart pointers.)
If I saw this code I would be very suspicious a memory leak was possible. On the surface it appears to be adding an allocated String* into a list<String*>. In my experience this is often followed by bad error handling code which does not properly free the allocated memory.
While this dangerous in many circumstances it is not necessarily a memory leak. Consider the following example:
class Container {
~Container() {
std::list<String*>::iterator it = list.begin();
while (it != list.end()) {
delete *it;
it++;
}
}
void SomeMethod() {
...
list.push_back(new String("hi"));
}
std::list<String*> list;
}
In this code there is no leak because the containing class is responsible for the memory allocated and will free it in the destructor.
EDIT
As aschepler pointed out there is still a leak if the push_back method throws an exception.
You are correct, provided nothing deletes the string when it is removed from the list.
Yes, this is a memory leak unles you somehow take steps to delete the contained pointers.
And the best way to accomplish that is to use a smart pointer. For example, Boost's shared_ptr or C++0x's shared_ptr.
list.push_back(new String("hi"));
Why are you allocating dynamic strings in the first place? Unless you want to communicate between different parts of your program by changing strings (which would be quite unusual), get rid of the pointer:
std::list<std::string> list; // note: no pointer!
list.push_back(std::string("hi")); // explicitly create temporary
list.push_back("hi"); // alternative: rely on coercion
No.
You can delete the object by doing:
delete list[i];
list.erase(list.begin() + i);
or clear the whole list by:
for (unsigned int i = 0; i < list.size(); ++i)
{
delete list[i];
}
list.clear();
Related
Valgrind reports that my code (showed below) is causing a memory leak.
view *vi = new view(IPs);
initialView = *vi;
//delete vi;
So, I added delete. But deleting vi makes initialView empty!! And causes several problems to valgrind. What shall I do?
By the way, This is the equal operator of class view!
view & operator = (const view& v){
vp = std::vector <process>(v.vp);
return *this;
}
A pointer is assigned a memory location from the heap or free store when you use the new command. The thing is, after using this memory location through the pointer, the programmer has to explicitly de-allocate that memory block using the delete command. Otherwise, the program will run out of dynamic memory and crash. Basically, that's what a memory leak leads to.
When the delete pointer is used, it simply resets the value of pointer to null and makes the memory block free for re usage. All you have to do is delete the pointer you use AFTER its designated use.
for example:
for(int i=0;i<1000;i++)
{
int* ptr=new int;
*ptr=i;
cout<<*ptr; // ptr has been used, don't need it anymore
delete ptr; //if you don't use this, memory leak will occur
}
You can replace this raw pointer with shared_ptr if possible. It's based on reference counting and hence can take care of freeing the memory when no one is pointing to it.
From your code, it's hard to tell. Which static variables are you referring to in the title?
For valgrind to be happy, you of course have to delete vi. In your code, I can't see any dependencies between initialView and vi after the assignment - the vector constructor creates a copy of v's process list, and if those processes are not deleted with vi, this should be fine. If there are other dependencies causing you problems, try to eliminate them.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
how to properly delete pointer?
i'm using std::vector to put a group of objects into it for later use, i am using DETAIL* pPtr = new DETAIL to create the pointer, and then inserting it into the vector.
the struct of DETAIL
struct DETAIL {
int nRef;
short sRandom;
};
Is this the best way to delete and erase a pointer within a vector leaving no room for memory leaks?
while(Iter1 != m_Detail.end())
{
if((*Iter1)->nRef == m_SomeVar)
{
delete *Iter1;
m_Detail.erase(Iter1);
break;
}
Iter1++;
}
Don't put raw pointers into the vector, instead use smart pointers such as std::shared_ptr. Then there is no need for delete, simply erase the pointer from vector and the pointed object will be automatically deleted.
My suggestion would be to use std::shared_ptr remove the shared pointer from the vector using erase and let it take care of deallocation. However there is nothing wrong with what you are doing but erase does not cause the vector to release the space it has allocated to hold the pointer. You can use shrik_to_fit to remove that allocated space.
i am using DETAIL* pPtr = new DETAIL to create the pointer
That's your first mistake, you're acquiring a resource (memory from the freestore and an object constructed in that memory) and not initializing an object that will take ownership and guarantee to deallocate the resources you acquired. The idiom to solve that first mistake is called Resource Acquisition Is Initialization.
It should be something like:
std::shared_ptr<DETAIL> pPtr(new DETAIL);
Or better yet:
std::shared_ptr<DETAIL> pPtr = std::make_shared<DETAIL>();
Or in C++03 replace std::shared_ptr with boost::shared_ptr (and boost::make_shared)
The next mistake is delete *Iter1; because almost any code that uses delete outside of a destructor is wrong (and all code that uses delete outside a destructor and is accompanied by a question about how to avoid memory leaks is definitely wrong.) If you use the RAII idiom you don't need to use delete because it happens automatically at the right time.
Also, why is your class called DETAIL? What's wrong with Detail instead?
I don't like answer like "never do" so I'll answer, but gives you some tricks to bypass the risk of freeing the vector without freeing the content.
if I understand well you have a vector of DETAIL pointers:
std::vector<DETAIL*> details;
So you want a method to remove and delete all pointed objects which refer to a certain m_SomeVar: (for now let's imagine it's a free function)
void free_references(int reference, std::vector<DETAIL*> & vector)
{
std::vector<DETAIL*>::iterator it = vector.begin();
while (it != vector.end())
{
if ((*it)->nRef == reference)
{
delete *it;
// erase() makes the original 'it' in an unknown state which can't be used
// erase will return a valid iterator which is, in this case, the following element
it = vector.erase(it);
}
else
{
++it;
}
}
}
As I understand in your code, the vector is member of a class. Which is good cause you'll be able to delete everything in the destructor.
However, I would use std::unique_ptr here to "give" the ownership of the pointer to the unique_ptr container inside the vector. And when the vector memory is free, the std::unique_ptr smart point make sure that the owned pointed object is freed.
I don't know if i fully understood it but have you tryied using the ZeroMemory macro?
int* func()
{
int* i=new int[1];
//do something
return i;
}
void funcc()
{
int* tmp=func();
//delete allocated memory after use
delete tmp;
}
should delete working as described in the second function be a correct use ?
I think I didn't allocate memory to it by new ? new was used in the first, to be sure.
It should be delete [] tmp; because you're doing array new, but otherwise, it's correct.
As others have stated, you should use delete[] to delete arrays, not delete.
But, if you're asking whether it's okay to delete tmp because the memory it points to wasn't allocated with new, then your premise is incorrect.
It was allocated with new. The address of the memory that you allocate within the function for i is passed back to be stored in tmp, so it does point to memory that was allocated by new.
You're correct that i itself is out of scope at that point but memory allocated by new survives the scope change on exit from the function. And, since you're storing its location into tmp, you still have access to it.
Hence the deletion (once you make it an array deletion with []) is quite valid.
This is Undefined Behaviourâ„¢. You can only use delete if you used new. If you used new[], you MUST delete[] it. More than that, this is hideously unsafe code- you need a smart pointer.
No. new T[] should match delete []t. And new T should match delete t. Otherwise, your code would invoke undefined bevavior.
And it doesn't matter if you do delete []tmp outside the function. Its okay to do so. All that you need to keep in mind that the form of delete.
My spidey-senses tell me that you're wondering whether the dynamically-allocated int that you create in func is the same one that you attempt to delete in funcc.
The answer is: yes. Although you don't use strictly the same pointer variable, both pointers point to the same object.
However, please remember to use delete[] (with the []) when you used new[] (with the []). Your code is broken until you fix this.
Also, try to avoid newing in one place and deleteing in another. Perhaps consider a std::vector instead, which is far less error-prone.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
How could pairing new[] with delete possibly lead to memory leak only?
( POD )freeing memory : is delete[] equal to delete?
Using gcc version 4.1.2 20080704 (Red Hat 4.1.2-48). Haven't tested it on Visual C++.
It seems that delete and delete [] works the same when deleting arrays of "simple" type.
char * a = new char[1024];
delete [] a; // the correct way. no memory leak.
char * a = new char[1024];
delete a; // the incorrect way. also NO memory leak.
But, when deleting arrays of "complex" type, delete will cause memory leak.
class A
{
public:
int m1;
int* m2; // a pointer!
A()
{
m2 = new int[1024];
}
~A()
{
delete [] m2; // destructor won't be called when using delete
}
};
A* a = new A[1024];
delete [] a; // the correct way. no memory leak.
A* a = new A[1024];
delete a; // the incorrect way. MEMORY LEAK!!!
My questions are:
In the first test case, why delete and delete [] are the same under g++?
In the second test case, why g++ doesn't handle it like the first test case?
This is all dependent on the underlying memory manager. Simply put, C++ requires that you delete arrays with delete[] and delete non-arrays with delete. There is no explanation in the standard for your behaviour.
What's likely happening however is that delete p; simply frees the block of memory starting at p (whether it is an array or not). On the other hand delete[] additionally runs through each element of the array and calls the destructor. Since normal data types like char don't have destructors, there is no effect, so delete and delete[] end up doing the same thing.
Like I said, this is all implementation specific. There's no guarantee that delete will work on arrays of any type. It just happens to work in your case. In C++ we call this undefined behaviour -- it might work, it might not, it might do something totally random and unexpected. You'd be best to avoid relying on undefined behaviour.
char * a = new char[1024];
delete a; // the incorrect way. also NO memory leak.
No. It doesn't gaurantee No memory leak. It in fact invokes undefined behavior.
delete and delete[] seemingly being equivalent in g++ is pure luck. Calling delete on memory allocated with new[], and vice versa, is undefined behaviour. Just don't do it.
Because that's undefined behavior. It's not guaranteed to break but it's not guaranteed to work either.
The delete expression calls the destructor of the object to be deleted before releasing the memory. Releasing the memory probably works in either case (but it's still UB), but if you use delete where you needed delete[], then you aren't calling all the destructors. Since your complex object itself allocates memory which it in turn releases in its own destructor, you are failing to make all those deletions when you use the wrong expression.
they technically aren't the same, they just get optimized down to the same meaning on non-complex types. complex types require the vectorized delete so that the destructor can be called for every object in the array you delete (just like vectorized new for constructors).
what your doing just free's the memory like its a pointer array.
What is happening here is that when you call delete, the space taken up by the objects is deleted. In the case of chars, this is all you need to do (although it is still recommended to use delete[] because this is just g++. The actual behavior of calling delete on an array is undefined in the c++ standard.).
In the second example, the space taken up by you array is deallocated, including the pointer m2. However, what m2 is pointing to is not also deleted. When you call delete[] the destructor on each object in the array is called and then what m2 points to is deallocated.
I'm working with std::list<std::string> in my current project. But there is a memory leak somewhere connected with this. So I've tested the problematic code separately:
#include <iostream>
#include <string>
#include <list>
class Line {
public:
Line();
~Line();
std::string* mString;
};
Line::Line() {
mString = new std::string("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
}
Line::~Line() {
//mString->clear(); // should not be neccessary
delete mString;
}
int main(int argc, char** argv)
{
// no memory leak
while (1==1) {
std::string *test = new std::string("XXXXXXXXXXXXXXXXXXXXXXXX");
delete test;
}
// LEAK!
// This causes a memory overflow, because the string thats added
// to the list is not deleted when the list is deleted.
while (1==1) {
std::list<std::string> *sl = new std::list<std::string>;
std::string *s = new std::string("XXXXXXXXXXXXXXXXXXXXXXX");
sl->push_back(*s);
//sl->pop_back(); //doesn't delete the string?- just the pointer
delete sl;
}
// LEAK!
// Here the string IS deleted, but the memory does still fill up
// but slower
while (1==1) {
std::list<Line> *sl = new std::list<Line>;
Line *s = new Line();
sl->push_back(*s);
//sl->pop_back(); //does delete the Line-Element
sl->clear();
delete sl;
}
return 0;
// this does not cause any noticable memory leak
while (1==1) {
std::list<int> *sl = new std::list<int>;
int i = 0xFFFF;
sl->push_back(i);
sl->clear();
delete sl;
}
return 0;
// This does not cause any overflow or leak
while (1==1) {
int *i;
i= new int [9999];
delete[] i;
}
}
Why does my string list cause a memory leak? Shouldn't deleting the list cause the destructors to be called on each contained string?
In the first case, the list class has no idea you allocated the string with new, and cannot delete it. In particular, the list only ever contains a copy of the string that you passed in.
Similarly, in the second case, you never free the line object s, and thus you leak memory. The reason why the internal string is deleted is because you have not correctly implemented a copy constructor. Thus, if you make a copy of a Line object, both of them will reference the same string pointer, and if you try to delete both of them, you are in trouble.
Your Line class needs a copy-ctor and an assignment operator that properly deal with the string pointer.
Alternatively, just have a std::string member rather than a pointer and let the string class handle the memory (that's what it's for).
Here's your leak:
while (1==1) {
std::list<Line> *sl = new std::list<Line>;
Line *s = new Line();
sl->push_back(*s);
//sl->pop_back(); //does delete the Line-Element
sl->clear();
delete sl;
}
STL collections store elements by value, allocating and releasing space for it. What you allocated you have to release explicitly. Just add delete s to the end of the loop.
If you have to store pointers, consider storing managed pointers like boost::shared_ptr, or look into Boost pointer container library.
On the second look, you don't need to allocate Line on the heap at all. Just change it to:
sl->push_back(Line());
And, as others noted, make sure Line's pointer members are properly managed in copy-constructor, copy-assignment, and destructor.
std::list<Line> *sl = new std::list<Line>;
Line *s = new Line();
sl->push_back(*s);
//sl->pop_back(); //does delete the Line-Element
sl->clear();
delete sl;
You forgot to delete s . You new'ed it, you have to delete it. As you're copying objects around(By stuffing them in a list) while managing memory in your Line class, you also have to provide a copy constructor and assignment operator for your Line class.
Others have addressed specifically why you have your leak - deleting a list of pointers does not delete the objects that are pointed to, and should not as a simple pointer gives no indication whether it was the only reference to that object ), but there are more ways than having to make sure you iterate the list on deletion to delete the pointers.
As far as the example here shows theres no reason to use pointers to anything at all, since you're using them when they enter the scope and discarding them when they leave the scope - simply create everything on the stack instead and the compiler will properly dispose of everything on exiting the scopes. Eg.
while (1==1) {
std::list<std::string> sl;
std::string s = std::string("XXXXXXXXXXXXXXXXXXXXXXX");
sl.push_back(s);
}
If you do need the pointer behaviour (to avoid having to duplicate objects that are linked to by many things etc. etc.) you should take a look at smart pointers, as these will remove many of the pitfalls as they can automatically handle the reference counting and semantics you require. (Specifically take a look at the boost smart pointers)
There are many types of smart pointer you can use depending on specific need and ownership semantic to represent.
The std::auto_ptr has strict ownership - if the pointer is "copied" the original is nulled and ownership transfered - there is only ever be one valid auto_ptr to the object. The object pointed to is deleted whenever the smart pointer with ownership goes out of scope.
Theres also boost shared pointers and weak pointers using reference counting to know when to free the object being pointed to. With Shared pointers each copy of the pointer increases a reference count, and the object pointed to is deleted whenever all the shared pointers go out of scope. A weak pointer points to an object managed by a shared pointer but does not increase the reference count, if all the parent shared pointers are deleted attempting to dereference a weak pointer will throw an easily catchable exception.
Obviously theres a lot more to the range of smart pointers, but I highly suggest taking a look at them as a solution to help with managing your memory.