std::auto_ptr, delete[] and leaks
Asked Answered
T

2

7

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

Trodden answered 29/7, 2009 at 7:32 Comment(2)
In most cases if you pair new with delete[] and vice versa for non-trivial types this doesn't cause a leak - instead the program simply crashes when trying to deallocate memory.Seltzer
You can try using boost::scoped_array instead of std::auto_ptrBriarwood
F
15

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.

Forgat answered 29/7, 2009 at 7:35 Comment(3)
Yes, I'm unlucky :) Thanks for explanation.Trodden
I compiled this but I am getting _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) error message, program crashes..this seems to indicate it is getting deleted twice but don't know how that could happenBoysenberry
The destructor of Foo would in fact be called iterCounttimes but note iterCount * sizeBig timesBoysenberry
S
3

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[].

Seltzer answered 29/7, 2009 at 7:35 Comment(3)
So as GMan says: it's sheer luck delete is equivalent to delete[] here?Mandarin
Well, yes, it's a result of the compiler trying to be clever and accidentially saving the developer.Seltzer
It's not a result of compiler being clever, it is rather the result of compiler being lazy and doing the easiest thing (which in this case means that memory allocation for one element and array when PODs are involved works precisely the same). Of course this is U.B., so it is "sheer luck" that it works in a given implementation - and IIRC there are some real implementations where it does not work.Christmann

© 2022 - 2024 — McMap. All rights reserved.