views:

193

answers:

6

Hello, all.

I am working on modifying a relatively large C++ program, where unfortunately it is not always clear whether someone before me used C or C++ syntax (this is in the electrical engineering department at a university, and we EEs are always tempted to use C for everything, and unfortunately in this case, people can actually get away with it).

My question is this:

if someone creates an object:

Packet* thePacket = new Packet();

Does it matter whether is is destroyed with delete thePacket; or free(thePacket); ?

I realize that delete calls the destructor while free() does not, but Packet does not have a destructor. I am having a terrible time stuck in a memory management swamp here and I'm thinking this may be one of the many problems. Please help.

Thanks in advance,

Dmitri

+12  A: 

Yes it does matter. For memory obtained using new you must use delete and use free for those obtained from malloc. new and malloc may use different data structures internally to keep track of what and where it has allocated memory. So in order to free memmory, you have to call that corresponding function that knows about those data structures. It is however generally a bad idea to mix these two types of memory allocation in a piece of code.

srean
`new` and `malloc` **may** use different data structures internally to keep track of memory allocations. They don't have to.
Ken Bloom
Thanks! Just the kind of answer I was looking for. <sarcasm> Yaay for going through other people's code to see what they used to create what... gonna be a fun. </sarcasm>
Dmitri
@Dmitri I hear you :) and you are most welcome. Time for the mighty grep
srean
@ken edited in the 'may' in the original. Thanks
srean
@Dmitri, valgrind can help you find mismatches.
Ken Bloom
I don't see where it is a bad idea to mix new and malloc as long as you always use the corresponding delete/free method. In fact there are several reasons to use malloc/realloc/free in code which otherwise use new/delete (i.e. managing an internal buffer which should be reallocated and so on.). Someone could even use other heap management functions (i.e. HeapAlloc and friends on windows systems). Or program an own memory pool. Why not mix that?
rstevens
@rstevens There's no problem mixing `new` and `malloc` -- just mismatching. However, you should consider that mixing may be a problem if it will lead you to mismatch.
Ken Bloom
+12  A: 

If you call free(), the destructor doesn't get called.

Also, there's no guarantee that new and free operate on the same heap.

You can also override new and delete to operate specially on a particular class. If you do so, but call free() instead of the custom delete, then you miss whatever special behavior you had written into delete. (But you probably wouldn't be asking this question if you had done that, because you'd know what behaviors you were missing..)

Ken Bloom
Thanks. See my comment on Omnifarious' post (i was reading from bottom up)
Dmitri
@Dmitri, I wasn't suggesting redefining `delete` as a solution -- I was pointing out as another potential problem. I've edited my answer to make that a little clearer.
Ken Bloom
If you override the global `new` and `delete` then you *have* to use `malloc()` and `free()`.
wilhelmtell
@wilhelmtell: no, you don't. You could preallocate a chunk of contiguous memory and do your own memory management inside of it (i.e. a special memory pool), or you could use some special system call provided by your operating system (e.g. `mmap` or `HeapAlloc`). You could also simply add special accounting to `new` and `delete`, and by mismatching `new` with `free` in the calling code, your accounting wouldn't get updated correctly when you `free` the data.
Ken Bloom
+4  A: 

You are absolutely right, it is NOT correct. As you said yourself, free won't call the destructor. Even if Packet doesn't have an explicit destructor, it's using an inherited one.

Using free on an object created with new is like destroying only what a shallow-copy would reach. Deep-destroying NEEDS the destructor function.

Also, I'm not sure objects created with new() are on the same memory map as malloc()'d memory. They are not guaranteed to be, I think.

Santiago Lezica
+4  A: 

Packet has a destructor, even if you haven't explicitly declared one. It has a default destructor. The default destructor probably doesn't actually do much, but you can't count on that being the case. It's up to the compiler what it does.

new and malloc also may have wildly different implementations. For example, delete is always called in a context where it has perfect information about the size of the data structure it's deleting at compile time. free does not have this luxury. It's possible that the allocator that new is using may not store the bytes at the beginning of the memory area stating how many bytes it occupies. This would lead free to do entirely the wrong thing and crash your program when freeing something allocated with new.

Personally, if getting people to do the right thing or fixing the code yourself is completely impossible, I would declare my own global operator new that called malloc so then free would definitely not crash, even though it would still not call the destructor at be generally really ugly.

Omnifarious
That's a pretty clever solution. I don't think we're quite that far up the creek, but definitely expands my horizons.
Dmitri
Liked the work around +1
srean
+2  A: 

In short, it is as bad as undefined behavior.

This is quiet self explanatory.

C Standard ($7.20.3.2/2) - "The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined."

Chubsdad
+1 for mentioning undefined behavior.
FredOverflow
+1  A: 

if someone creates an object:

Packet* thePacket = new Packet();

Does it matter whether is is destroyed with delete thePacket; or free(thePacket); ?

Yes it does matter. free (thePacket) would invoke Undefined Behaviour but delete thePacket would not and we all know Undefined Behaviour may have disastrous consequences.

Prasoon Saurav
+1 for mentioning undefined behavior.
FredOverflow