Why this code does not cause memory leaks?
int iterCount = 1000;
int sizeBig = 100000;
for (int i = 0; i < iterCount; i++)
{
std::auto_ptr<char> buffer(new char[sizeBig]);
}
WinXP sp2, Compiler : BCB.05.03
Because you're (un)lucky. auto_ptr calls delete, not delete []. This is undefined behavior.
Try doing something like this and see if you get as lucky:
struct Foo
{
char *bar;
Foo(void) : bar(new char[100]) { }
~Foo(void) { delete [] bar; }
}
int iterCount = 1000;
int sizeBig = 100000;
for (int i = 0; i < iterCount; i++)
{
std::auto_ptr<Foo> buffer(new Foo[sizeBig]);
}
The idea here is that your destructor for Foo will not be called.
The reason is something like this: When you say delete[] p, the implementation of delete[] is suppose to go to each element in the array, call its destructor, then free the memory pointed to by p. Similarly, delete p is suppose to call the destructor on p, then free the memory.
char's don't have a destructor, so it's just going to delete the memory pointed to by p. In my code above, it is not going to destruct each element in the array (because it's not calling delete[]), so some Foo's will leave their local bar variable un-deleted.
The auto_ptr will only live for the duration of the loop iteration and will release the object connected to it on iteration completion.
The compiler can see that in this case new[] can allocate space in the same way as new - without storing the number of elements anywhere since there's no need to call trivial char destructors - and that's why later when delete is called by the auto_ptr's destructor instead of delete[] it causes no problems since the memory block has actually been allocated in the new's way and that allocation can be paired with delete.
This is an example of a thing not to do. It's up to the compiler to decide whether to replace new[] with new. Using delete instead of delete[] and vice versa is undefined behaviour.
See Why would you write something like this? (intentionally not using delete [] on an array) for discussion of delete vs delete[].
Related
I want to create some continuous memory, and use bunch of shared_ptr pointing to them.
int main() {
int *arr = new int[5];
for (int i = 0; i < 5; i++) {
std::shared_ptr<int> ptr(&arr[i]);
}// when the loop scope end, the shared_ptr will be destroyed.
};
this code will give an error:
pointer being freed was not allocated
my expectation: when the scope of loop end, the shared_ptr will be destroy, and the element in array will be destroyed successively.
But it seems that when the first pointer is destroyed, the whole array is freed.
I also tried std::allocator, still not work.
So is there any way that can allocate continuous memory, and I can use shared_ptr pointing to each of them, then when the first element is freed, the whole memory won't be freed together?
Its an "interesting" thing to want to do but if you really want to do it you can use the shared_ptr's aliasing constructor.
int main() {
std::shared_ptr<int[]> arr(new int[5]);
for (int i = 0; i < 5; i++) {
std::shared_ptr<int> ptr(arr,&arr[i]);
}
};
Without c++17 you need to do a little more:
int main() {
std::shared_ptr<int[]> arr(new int[5], std::default_delete<int[]> {});
for (int i = 0; i < 5; i++) {
std::shared_ptr<int> ptr(arr, &arr.get()[i]);
}
};
The array will be deleted when the last element shared_ptr is destroyed (assuming the array shared_ptr itself has already been destroyed/reset).
You are misusing shared_ptr. The memory you allocated was attributed with operator new[], it should thus be freed with operator delete[].
Furthermore, since the allocated object is an array, any ownership semantics should be applied to the whole array and not divided across its elements!
You can achieve by specifying a custom deleter for your shared_ptr: (C++11/14)
std::shared_ptr<int> arr_ptr(new int[5], std::default_delete<int[]> {});
Or simply using an array type specialization of shared_ptr (C++17):
std::shared_ptr<int[]> arr_ptr(new int[5]); // Will call delete[] upon destruction.
I was reading this question Does calling a destructor explicitly destroy an object completely? where this situation comes up in code.
Object* aWidget = new Widget(); //allocate and construct
aWidget->~Object(); //destroy and DON'T deallocate
From the answers, I undrestand that the memory region is in fact not deallocated in this situation. My question is (more out of curiosity than anything):
How can I delete the memory pointed to by aWidget after the two lines of code above have executed? I would assume calling delete aWidget; would fail because it would try to run the destructor on an already-destructed object. Could you call free(aWidget) or something like that instead to just target the memory?
free would, factually speaking, be my best guess. However I don't think you can do anything without invoking UB. How did you arrive at a requirement to invoke the destructor like that?
Calling free on an object allocated with new is undefined behavior.
I suggest you keep it simple, and call delete.
However, if you want to do this, you can, in some cases, call delete even if you previously called the destructor explicitly. If you call it explicitly, you can view it as a function. The memory isn't freed, so I'm guessing setting member pointers to NULL after you destroy them would be enough to prevent you from running into any trouble. (because calling delete on a NULL pointer is a no-op).
For example, the following should be ok:
class A
{
public:
int * x;
A()
{
x = new int[10];
}
~A()
{
delete[] x;
x = NULL;
}
};
int main()
{
A* a = new A;
a->~A();
delete a;
return 0;
}
I have allocated and array of Objects
Objects *array = new Objects[N];
How should I delete this array?
Just
delete[] array;
or with iterating over the array's elements?
for(int i=0;i<N;i++)
delete array[i];
delete[];
Thanks
UPDATE:
I changed loop body as
delete &array[i];
to force the code to compile.
Every use of new should be balanced by a delete, and every use of new[] should be balanced by delete[].
for(int i=0;i<N;i++)
delete array[i];
delete[] array;
That would be appropriate only if you initialized the array as:
Objects **array = new Objects*[N];
for (int i = 0; i < N; i++) {
array[i] = new Object;
}
The fact that your original code gave you a compilation error is a strong hint that you're doing something wrong.
BTW, obligatory: avoid allocating arrays with new[]; use std::vector instead, and then its destructor will take care of cleanup for you. Additionally it will be exception-safe by not leaking memory if exceptions are thrown.
Just delete[] array is sufficient. It is guaranteed that each element of the array is deleted when you delete an array using delete[] operator.
As a general rule you should delete/delete[] exactly those things that you allocated with new/new[]. In this case you have one allocation with new[], so you should use one call to delete[] to free that allocated thing again.
That the deletes in the for-loop won't compile is also a good indication that they are not the right way to do it.
Not only is
delete [] array;
enough, but if you do
for(int i=0;i<N;i++)
delete &array[i];
delete[] array;
you'll be causing undefined behavior, because
delete &array[i];
will be deleting things that weren't returned by a new operation.
Not to mention that the subsequent delete[] array; will call the destructor for all the objects that just had destructors called in the loop.
So don't do that.
delete [] array
is enough.
I have an abstract Base class and Derived class.
int main ()
{
Base *arrayPtr[3];
for (int i = 0; i < 3; i++)
{
arrayPtr[i] = new Derived();
}
//some functions here
delete[] arrayPtr;
return 0;
}
I'm not sure how to use the delete operator. If I delete array of base class pointers as shown above, will this call derived class objects destructors and clean the memory?
You have to iterate over the elements of your array, delete each of them. Then call delete [] on the array if it has been allocated dynamically using new[].
In your sample code, the array is allocated on the stack so you must not call delete [] on it.
Also make sure your Base class has a virtual destructor.
Reference: When should my destructor be virtual.
No, you have to explicitly delete each item in the array:
for (int i = 0; i < 3; ++i)
{
delete arrayPtr[i];
}
You should instead do:
for ( int = i; i < 3; i++ )
{
delete arrayPtr[i];
}
And you shouldn't do delete[] arrayPtr; as you're trying to free/delete a stack allocated arrayPtr.
Another thing to consider is using a std::vector of pointers instead of an array. And if you're using a compiler that implements TR1, you could also use a std::vector of std::tr1::shared_ptr instead of raw pointers, and than you wouldn't need to worry about deleting those objects yourself.
Example:
{
std::vector< std::tr1::shared_ptr<Base> > objects;
for (int i=0; i < 3; ++i)
{
objects.push_back(std::tr1::shared_ptr<Base>(new Derived()));
}
} // here, once "objects" exit scope, all of your Derived objects are nicely deleted
You have to delete the members of the array individually. You must also make sure that your base class has a virtual destructor. You might also want to consider making it an array (or better still a std::vector) of smart pointers, such as boost::shared_ptr.
No, you can not do that. As others suggested you have to go through each item and delete it. It's a very simple rule to remember. If you allocated using new then use delete, and if you had used new[] then use delete[]
Notice what's absent:
int main() {
boost::ptr_vector<Base> v;
for (int i = 0; i < 3; i++) v.push_back(new Derived());
// some functions here, using v[0] through v[2]
}
Check Boost's pointer containers out.
Operator delete must match operator new on that pointer, if it was allocated with new[], you must call delete[] and vice versa;
int* pInt = new int;
delete pInt; OK
delete [] pInt; WRONG
int[] pIntArr = new int[3];
delete [] pIntArr; OK
delete pIntArr; WRONG
In your case there is something else wrong - you are trying to delete that was allocated on the stack. That wouldn't work.
You must delete each pointer individually in this particular case.
What you have there is undefined behaviour -- a bug. Each call to new needs to be matched with a delete; each call to new[] needs to be matched with a delete[]. The two are separate and can't be mixed.
In the code you posted, you have an array of pointers to Base allocated on the stack. You're then calling delete[] on an array allocated on the stack -- you can't do that. You can only delete[] an array allocated on the heap with new[].
You need a call to delete for each element allocated with new -- or preferably, look into using a container class, such as std::vector, instead of using an array.
Make sure Base has a virtual destructor. Then like fretje outlined, delete each element in the array, then delete the array.
You should be using std::vector for the array. That said, you should really be using a container made for this sort of thing. (So you don't accidentally fail to delete all the elements, which will definitely be the case if an exception gets thrown!) Boost has such a library.
You're mixing paradigms -- The array delete operator is designed to free memory allocated by the array new operator, but you're allocating your array on the stack as an array of pointers and then allocating an object for each array member. In your code, you need to iterate through the array.
To use the array new operator, you'd declare like this:
Base *array;
array = new Base[3];
/* do stuff */
delete[] array;
This allocates a contiguous memory area for the three objects -- note that you've got an array of Base objects, not an array of pointers to Base objects.
No, this doesn't quite do what you want.
There are two points to watch out for here:
The syntax delete[] arrayPtr is used if you dynamically allocate the array, like this:
arrayPtr = new (Base *)[mylength];
In your case, however, you have a statically allocated array, so there is no need to delete it. You do, however, need to delete the individual elements in the array:
for ( int = i; i < 3; i++ )
delete arrayPtr[i];
The second point you need to take care of is to make the destructor of the class Base virtual:
class Base
{
virtual ~Base();
/* ... */
};
This ensures that when you call delete on a Base * that is actually pointing to a Derived, the destructor of Derived is called, not just the destructor of Base.
Please see the following code and its output - please explain me the code
void abc(int);
class A
{
public:
A()
{
cout<<"Constructor Called";
}
~A()
{
cout<<"Destructor called";
}
};
int main()
{
try
{
abc(-1);
}
catch(int p)
{
cout<<p<<endl;
}
return 0;
}
void abc(int p)
{
A * Aptr = new A[2];
if(p<0)
throw p;
}
Output:
Constructor Called
Constructor Called
-1
can anyone explain why is the destructor not being called as in the case of normal stack unwinding
This pointer:
A * Aptr = new A[2];
is a raw pointer. When it goes out of scope only the pointer itself is destroyed - nothing is done to the array it points to. So the array is not delete[]'ed and the destructors are not called. It's a typical example of a memory leak.
There're three typical solutions to the problem:
allocate the array itself on stack
use std::vector
use a smart pointer (not std::auto_ptr - it is not suitable for using with arrays.
The destructor is not called because the objects you allocate are never deleted. You would get the same output if you removed the throw.
If, on the other hand, you changed your function into this:
void abc(int p)
{
A A_array[2];
if (p<0)
throw p;
}
You would see that the destructor was called.
As mentioned elsewhere, C++ pointers do NOT delete the memory they point to when going out of scope. You have a few options:
The hard way - try and do the memory management yourself. This way lies memory leaks and buffer overflows. Try not to do this.
void abc(int p)
{
A * Aptr = new A[2];
if(p<0)
{
delete [] Aptr;
throw p;
}
delete [] Aptr;
}
Put the array on the stack and let the normal stack unwinding handle it:
void abc(int p)
{
A Aptr[2];
if (p<0)
throw p;
}
Instead of using a raw pointer to point to the newly allocated array, hold onto it using a smart pointer class like scoped_array or shared_array, or some other RAII class:
void abc(int p)
{
boost::scoped_array<A> Aptr (new A[2]);
if(p<0)
throw p;
}
}
2 and 3 are really the only safe options in C++ code that uses exceptions - if you use raw pointers and manual memory management, you WILL end up with memory leaks sooner or later. No matter how careful you are, exception safe code pretty much requires RAII.
In addition to the suggestions concerning boost::shared_array and boost::scoped_array you could also just use std::vector:
std::vector<A> array( 2 );
if( p < 0 )
throw p;
Note that your types should be copyable if you go this route, however, as std::vector will copy them around during insert or when internally resizing, et cetera.
Could it be because you are not calling delete on your A class? If you don't delete a dynamically allocated class the desnstructor is not called.
because you allocated on the heap. What gets freed are the variables holding the pointer to the array of objects. Not the objects themselves.
Aptr is a heap-allocated variable, not a stack variable. You need to explicitly delete it for the destructor to be called (and to free the memory).
If you would instead do this:
A a[2];
and not
A *Aptr = new A[2];
you'd get the destructor called.
Anything you allocate dynamically you will have to deallocate yourself.
You created the object on the heap. The destructor will be callen when you delete the object.
If you don't create the object on the heap, the destructor will be called as you expected.