What if, memory allocated using malloc is deleted using delete rather than free

I came across an issue which I could not resolve.

My question is, if I used malloc to allocate memory and then memory block is delete using delete? The general thumb rule is

If we allocate memory using malloc, it should be deleted using free.

If we allocate memory using new, it should be deleted using delete.

Now, in order to check what happens if we do the reverse, I wrote a small code.

#include<iostream>
#include<cstdio>
#include<cstdlib>

using namespace std;

class A
{
  int p=10;
public:
  int lol() {
    return p;
  }
};

int main()
{
  int *a = (int *)malloc(sizeof(int)*5);
  for(int i=0; i<4; i++) {
    a[i] = i;
    cout << a[i] << endl;
  }

  delete(a);
  // Works fine till here..

  A b;
  cout << b.lol() << endl;
  free(b); // Causes error.     

  return 0;
}

The error which I get is:

error: cannot convert ‘A’ to ‘void*’ for argument ‘1’ to ‘void free(void*)’

I am unable to understand why is this happening. Please explain.


ANSWERS:


When you call delete a pointer, the compiler will call the dtor of the class for you automatically, but free won't. (Also new will call ctor of the class, malloc won't.)

In you example, a char array apparently don't have a dtor, so delete does nothing but return the memory. That's why it's okay. (Or vise versa, new a char array and then free it.)

But there can still be a problem: what if new and malloc are borrowing memory from different heap manager?

Imagine that, you borrow money from people A, and return to people B later. Even if you are okay with that, have you ever consider A's feeling?

BTW, you should use delete [] pArray; to free an array allocated using new[].


The free function expects a pointer to memory allocated by malloc. The compiler is simply telling you that did not pass it a pointer, a fact that it can readily prove. I guess you meant to create an object with new and then call free on the address of that object. But you did not call new.

When you correct this you may well find the free succeeds but you should not read anything significant into any such success. You know the rules, they are clearly stated in your documentation. It is incorrect to do what you are attempting. The behaviour is undefined. There's little to be gained from an experiment like this. You won't learn anything about why the C memory management functions cannot be paired with C++ memory management functions.

The problem with your experiment is that is has no power. You can just show the outcome for one specific scenario. But these functions are designed to work across the board. How are you going to test every single possible scenario?

Never program using trial and error. You must always understand the rules and priciples behind what you do.


You didn't create b using new so you are not testing the intended hypothesis. (Also, the name of b is not a pointer.)

Anyway, malloc/new and delete/free work interchangeably only as long as their implementations are interchangeable. In simple cases and on simpler platforms this is more likely, but it's a risky bet in the long term or as a habit.

For example, the array form of new, when applied to a class with a nontrivial destructor, requires the implementation (compiler, runtime, etc.) to remember the size of the array so that delete may call the destructor for each array object. There is almost nowhere to put such information but in the dynamically allocated block itself, preceding the memory location referred to by the pointer returned by new. Passing this pointer to free would then require the memory allocator to determine the actual start of the allocation block, which it may or may not be able to do.

More generally, new and malloc may refer to completely different memory allocators. The compiler, runtime library, and OS work together to provide memory to your program. The details can change as a result of switching or upgrading any of these components.


From the documentation,

void free (void* ptr); 

ptr::

Pointer to a memory block previously allocated with malloc, calloc or realloc.

And what you are passing is not a pointer, so it complains.

 A *b = new A();
 cout << b->lol() << endl;
 free(b); // Will Not cause error

Your b variable is not a pointer, but a stack-allocated A. If you want to try this experiment, then you'd want to say

A* b = new A;
free(b);

I'm all for experimentation, but I'm not sure what you were trying to achieve here.

In C++, operator new doesn't just allocate memory, it runs constructors too. Similarly, delete runs destructors for you (taking polymorphic classes into account), as well as freeing the returned memory. On the other hand, malloc() and free() are just C library routines which (from a programmer's point of view) do nothing more than request a chunk of memory from the operating system, and then hand it back.

Now, for a simple, POD class with trivial constructors and destructors, you might be able to get away with mixing up C and C++ memory allocation, because there's nothing C++-specific to be done. But even if you do, what does it prove? It's undefined behaviour, and it probably won't work on another compiler. It might not work tomorrow.

If you use any C++ features -- inheritance, virtual functions, etc etc, it very definitely won't work, because new and delete have to do a lot more work than just allocating memory.

So please, stick to the rules! :-)


No, it is not a rule of thumb that you should not mix new/free or malloc/delete.

Sure, it might be possible to use free to relinquish an allocation you obtained with new without a crash, but it is highly implementation/system specific.

Ignoring the fact that you're bypassing destructors or writing code that will corrupt memory on some systems, the more fundamental, more basic C++ consideration is really simply this:

malloc/free are global, system functions, while new and delete are operators.

struct X {
    void* operator new(size_t);
    void operator delete(void* object);
};

Sure - you can borrow a book from Amazon and return it to your local library: go there late one night and leave it on their front door step.

It's going to have undefined behavior, up to and including your getting arrested - and I'm talking about mixing new/free again here :)

Put another way: malloc and free deal with raw memory allocations, while new and delete deal with objects, and that's a very different thing.

void* p = new std::vector<int>(100);
void* q = malloc(sizeof(*q));

Many good reasons have already been given. I'll add one more reason: the new operator can be overriden in c++. This allows the user to specify their own memory management model if they so desire. Although this is pretty uncommon, its existence is just one more reason why malloc and new, delete and free cannot be used interchangeably. This is for the reason described by @Patz.



 MORE:


 ? C: malloc(), free() and then again malloc() does work same always?
 ? Heap corruption while freeing memory
 ? Heap corruption while freeing memory
 ? Heap corruption while freeing memory
 ? heap corruption detected after normal block(#174)
 ? Heap corruption when trimming delayed free queue
 ? Heap corruption on free(...)
 ? Heap corruption while freeing memory in a recursion function
 ? Heap Corruption double freeing memory
 ? trying to free allocated memory generate heap error