>>4
On most implementations, new/delete are just calls to malloc/free. The only way they're superior is that new is typesafe, in the sense that it returns the asked pointer, and the allocation looks a bit more 'pretty' than the usual
type* var = (type*)malloc(sizeof(type),count); (+maybe memset to zero it, if needed) or
type* var = (type*)calloc(count,sizeof(type)). I tend to use
calloc most of the time, instead of malloc, except when I know for sure that the memory will be fully overwritten/initialized (for example, I would use
malloc when reading a whole file from disk, since there's no reason to null everything, just to have it overwritten by the file from disk). Of course, if you're using SEPPLES, you already have more problems, so just switching because you want to use new/delete is silly.
Fragmentation isn't really that big of an issue, in the worst case, it just means you can't alloc big blocks of memory if you've used up a lot of memory and fragmented it badly. It could also be slightly bad for those that still have paging files, but those people have a lot more to worry than malloc/free fragmenting the heap.
If you're that worried about fragmentation, you have a few options:
1) Quick&Dirty, but simple solution used by most people: use the OSes page allocator (on Windows - VirtualAlloc/VirtualFree, on *nix - mmap/munmap). This is useful especially if the memory blocks are very large and short-lived. You can make a compatibility layer if you desire portability (#IFDEF's or whatever your language offers).
2) Proper solution (for low-level languages), but a huge pain to use.
Make a handle <-> memory area (heap or pages, depending on how you design your system). Before use, call a lock method/function on the handle to acquire its current pointer. Using lock will also set a flag which forbids the memory manager to re-arrange blocks of memory. When you're done using, you should call an unlock method/function. You can have another thread compact the memory areas/realloc as you need to avoid fragmentation, or have it done on alloc/free operations or only when needed (not enough space). Your memory compactor should avoid any locked blocks. Alloc function should return a handle to the memory adress, free function should receive a handle and free the memory block represented by the handle. Some syntax sugar in the form of macros can be provided (in a Lispy language, it could be
with-pinned-memory, altough various managed languages provide similar with* constructs) to make things easier for the user(so he doesn't have to lock/unlock everything by hand - you're now adding even more needed bookkeeping than the usual malloc/free bookkeeping).
It might be worth mentioning that if you're on Windows and the application doesn't have to be portable, GlobalAlloc/GlobalFree/GlobalHandle/GlobalFree/GlobalLock/GlobalReAlloc/GlobalCompact(obsolete)/GlobalSize/GlobalUnlock and a few other functions provide this functionality without you having to implement it from scratch.
It remains without saying that you should not free/unmap memory alloced by such systems in different ways than they were mapped.
I have my doubts if this method is really worth using. The quick&dirty solution is usually enough for most projects and requires little changes to overall code, compared to this.
3) Proper solution (for high-level languages). Very easy to use.
Just use a compacting gc or whatever the language provides, and forget about memory management, at least unless you really have to do it for some reason (use FFI or specific library functions to do it then).