Sign in to follow this  
GunstarGreen

Recent change in C++'s delete/delete [] ?

Recommended Posts

I'm a programming intern who was fixing memory leaks earlier today. A senior programmer was helping me debug some corruption issues when I noticed he wrote a "delete" line for a void pointer that pointed to an array on the heap. I said, "actually, you should use delete [] there" and he said it didn't matter. My education told me that it most certainly did matter, but he was moving at a mile a minute and I had to pay attention to the next thing he did without asking him about it. And I forgot to ask him about it until now, and now he's not here anymore. ANYWAY. My question is this: has there been some change to delete that makes it interchangeable with delete [] recently? At my college I believe we use the 7.1 compiler to do our work (whatever's the default compiler for 2003 .NET), and the instructors drilled into us how important it was not to mix up delete and delete []. If there wasn't a change, is there some special case implementation for deleting void pointers? (What I thought was best was to cast it to a char pointer and then call delete [] on it). Edit: forgot to mention that the pointer actually points to a block of memory that was memcpy()'d over from a different pointer so as to do a deep copy. Is that relevant? Edit #2: The last "delete" was "delete" and not "delete []". Fixed the brain typo. Thanks in advance.

Share this post


Link to post
Share on other sites
It's bad style, but on MSVC with arrays of primitive and POD types you can get away with using delete instead of delete []. However it's fragile code which will go wrong if you ever deal with a class type. Of course the fact that you're dealing with a void pointer in the first place is a warning sign in and of itself.

Share this post


Link to post
Share on other sites
Calling delete on a void pointer is somewhat dubious since the compiler won't know what destructor to call. The major difference between delete and delete[] is that delete[] will call the destructor for every item in the array but it's perfectly possible for compilers to use different memory allocation schemes for new and new[] which is another good reason to pair the right versions of new and delete. Assuming new and new[] use the same allocator calling the wrong delete may or may not be safe depending on how the compiler chooses to store the information about how many elements are in the array that it needs to call the right number of destructors.

If you're just dealing with arrays of primitive types there's a reasonable chance you'll get away with using delete instead of delete[] but it's still bad style. If you have to work with void pointers I think you're better off using malloc and free to be explicit that you're dealing with raw chunks of memory rather than objects.

Share this post


Link to post
Share on other sites
Calling delete on a void pointer has well defined semantics: it calls ::operator delete(void *), which in turn should deallocate the memory. It's counterpart is the ::operator new(size_t) which allocated uninitialized memory. They're roughly equivalent to malloc()/free().

Share this post


Link to post
Share on other sites
The OP said the void pointer pointed to an array on the heap though which suggests the memory was allocated using regular new[] on a typed array. The memory might be freed correctly (if new[] and new allocate the same way and the extra array information doesn't screw things up) but it seems like bad style to me to delete through a void pointer memory that was allocated with a type, I suspect it's actually undefined though I don't have the standard to hand to check.

I guess using ::operator new(size_t) together with ::operator delete(void*) rather than malloc and free is actually the way to go if you really want a chunk of untyped memory though since it means all your memory allocations go through the same pair of functions.

Share this post


Link to post
Share on other sites
What I thought the problem WOULD be, is that calling delete on a void pointer deletes a seemingly unknown amount of data. I was taught that new [] and delete [] should be used together because new [] also allocates data about the allocation, i.e. number of objects among other things, which regular new does not. Likewise, delete [] examines that data to know how many objects to delete, while delete deletes only the first object.

It's true that what inspired me to make this topic was a void pointer pointing to non-class chunks of data (huge arrays either of floats or of unsigned ints), and I wasn't worried about destructors being called. I admit that I probably should have been if I was even thinking about the issue at all, but I was only thinking "wait-one-second, how does it know just how much to delete if it's not a delete []?"

Share this post


Link to post
Share on other sites
Quote:
Original post by GunstarGreen
I'm a programming intern who was fixing memory leaks earlier today. A senior programmer was helping me debug some corruption issues when I noticed he wrote a "delete" line for a void pointer that pointed to an array on the heap. I said, "actually, you should use delete [] there" and he said it didn't matter. My education told me that it most certainly did matter, but he was moving at a mile a minute and I had to pay attention to the next thing he did without asking him about it. And I forgot to ask him about it until now, and now he's not here anymore. ANYWAY.

My question is this: has there been some change to delete that makes it interchangeable with delete [] recently? At my college I believe we use the 7.1 compiler to do our work (whatever's the default compiler for 2003 .NET), and the instructors drilled into us how important it was not to mix up delete and delete []. If there wasn't a change, is there some special case implementation for deleting void pointers? (What I thought was best was to cast it to a char pointer and then call delete [] on it).

Edit: forgot to mention that the pointer actually points to a block of memory that was memcpy()'d over from a different pointer so as to do a deep copy. Is that relevant?

Edit #2: The last "delete" was "delete" and not "delete []". Fixed the brain typo.

Thanks in advance.


0) If you can afford it (in terms of keeping your job), question why you're using void* and (cough, sputter) memcpy() at all.

1) On some compilers you may get away with it. It's not standard. new pairs with delete. new[] pairs with delete[]. Even for primitive types, even for an array of one element, even for anything else you could possibly think of that might make a difference.

Besides which, the fact that "Mr. Senior Programmer" wouldn't *automatically* type delete[] for something he knew had been new[]ed (or, orders of magnitude worse yet, would allow it to not be known at compile-time whether new or new[] would be used for that pointer, or would know but not make use of the knowledge) suggests that a bit of re-training is in order.

Share this post


Link to post
Share on other sites
Basically it knows the same way that free() knows how to delete the right amount after a malloc() (literally true for MSVC). This is implementation defined, but generally involves writing the amount allocated before the block allocated. And since ::operator new() and ::operator delete() internally call malloc() and free() under MSVC it boots the bookkeeping responsibilities to the CRT. But again, don't do this crap in your code.

Share this post


Link to post
Share on other sites
The void pointers really bug me too. I don't know why they're void pointers. The type is always known. I guess maybe someone wanted to plan ahead and allow arbitrary types to be used? Which is still silly because you're choosing between 32 bit float types or 64 bit float types. I don't know, and I don't especially need to know why the team who wrote this thought a void pointer was at all useful. And the senior programmer I mentioned doesn't have the power to change it either, we're both writing tools for engine code that some team from Europe wrote.

As for the memcpy, I don't think it's bad programming, at least not in the code I'm using. We're copying extremely raw data: no pointers, no classes, no named anything. Just a few hundred byte's worth of vertex data that we need our own deep copy of.

Share this post


Link to post
Share on other sites
Quote:
Original post by GunstarGreen
As for the memcpy, I don't think it's bad programming, at least not in the code I'm using. We're copying extremely raw data: no pointers, no classes, no named anything. Just a few hundred byte's worth of vertex data that we need our own deep copy of.


Doesn't matter. Use std::copy. It's type-safe, will call constructors when required, will optimize to a memcpy-equivalent when possible, and doesn't require you to add a parameter to communicate the size of the type (because it's templated).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this