5

I know the free operation in C is to tell the compiler this particular memory block is free for compiler to use for further allocation, but the memory is not released.

What about the delete in C++? the same as free?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • Yes, it's the same. But you can overload new/delete implementations and do your own thing http://stackoverflow.com/q/4261963/176769 – karlphillip Jul 25 '11 at 13:26
  • 4
    @karlphilip delete will call the destructor, free won't do that, and that's a pretty huge difference – stijn Jul 25 '11 at 13:27
  • 1
    You don't tell the compiler, you tell the runtime. And the memory may or may not be actually returned to the operating system depending on implementation-specific conditions. Usually small-blocks are obtained from ever-growing heap (so reused but not returned) while large-blocks are obtained from system as separate entities (using mmap or similar) and returned to system when freed. – Jan Hudec Jul 26 '11 at 05:47

4 Answers4

20

There are two notions of delete in C++: One is the operator, declared as ::operator delete(void*), which basically only frees up the memory and isn't usually thought about by most programmers. The other is the delete expression, delete p;, where p is a T*. The expression invokes the destructor of the object pointed to by p (and then frees the memory), which is a crucial language feature of C++ that has no analogue in C.

As a rule of thumb, you pair new expressions with delete expressions, and malloc() function calls with free() function calls:

T * p = new T;        // constructor called!
delete p;             // destructor called!

void * x = malloc(5); // just raw memory
free(x);              // freed

Advanced part (not in response to the OP's question)

Dynamic object lifetime in C++ follows this general pattern: Allocate, construct, destroy, deallocate. The standard new expression performs allocation and construction, while the standard delete expression performs destruction and deallocation.

You could write out the process manually:

T * p = (T*)::operator new(sizeof(T));   // allocate raw memory
p = new (p) T;                           // call the constructor ("placement new")

/*...*/

p->~T();                                 // destroy the object
::operator delete(p);                    // deallocate the memory

In fact, if you really wanted to implement Baby's First C++, you could define the operators as just as malloc/free:

void * operator new(size_t n) { return malloc(n); }
void   operator delete(void * p) { free(p); }

The real C++ magic happens by virtue of the new and delete expressions: The standard new expression invokes the constructor (a new expression is the only way to call a constructor in C++!) after allocation, while the standard delete expression invokes the destructor before deallocation.

Why "standard expression"? Well, you can also define and overload many other versions of new and delete operators. However, there is an important asymmetry: While you can use a custom new operator in a custom new expression (generally dubbed "placement new"), there is no equivalent "placement-delete" expression. So whenever you use a custom new expression, you have to manually invoke the destructor before calling the matching custom delete operator:

T * p = new (A, B, C) T;                          // some custom new expression

// Entirely equivalent version:

T * p = (T*) ::operator new(sizeof(T), A, B, C);  // this is your custom overload
T * p = new (p) T;                                // std. placement-new expression calls constructor

/* ---- later ---- */

p->~T();                                          // Must destroy manually!
::operator delete(p, A, B, C);                    // your matching custom overload

Note that there does not exist a custom delete expression delete (A,B,C) p'!

For completeness, the standard placement new operator, whose only purpose is to call a constructor, is mandated by the standard to take the following form:

void * operator new(size_t, void * p) { return p; }

It's matching delete operator is also mandated, name to do nothing:

void operator delete(void * p, void *) { }

You can see in the above general example why this is necessary.

It is important always to overload custom versions of new and delete in pairs! The reason is that if the object construction fails with an exception inside the constructor, then the memory is released by a call to the delete operator that matches the offending new expression.


Second update: To be exception-safe, we have to consider that the constructor of T might throw:

Version 1:

try {
  T * p = new (A, B, C) T;
  /* ... */
  p->~T();
  ::operator delete(p, A, B, C); // automatically invoked if T::T() throws!
}
catch(...) { }

Version 2:

void * addr = ::operator new(sizeof(T), A, B, C);
try {
  T * p = new (addr) T;  // might throw
  /* ... */
  p->~T();
  // ::operator delete(p, addr); // ditto as in (1), but does nothing
}
catch(...) { }
::operator delete(addr, A, B, C);
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    To be more precise, `delete` doesn't invoke the destructor; but compiler puts the call to destructor before wherever it finds `delete` operator. By the time you enter the function block of `delete`, the destructor is already called. – iammilind Jul 25 '11 at 13:35
  • @iammilind: Your wording is a bit imprecise: If you say `::operator delete(p);`, the destructor will not get called. The destructor call is a consequence of the delete *expression*. – Kerrek SB Jul 25 '11 at 13:36
  • 3
    The "raw" calling sequence could be written out manually like this: `T * p = (T*)::operator new(sizeof(T)); p = new (p) T; p->~T(); ::operator delete(p);` You'd be insane to write that :-) – Kerrek SB Jul 25 '11 at 13:40
  • @Kerrek: Why don't you add the comments into the question text? It'd be appropriate when you're extending your own answer. As for the explicit sequence, it's important when you are defining some data structures or allocators (as in custom allocator for STL containers) for them. Things like `std::vector` have to allocate block of memory, but initialize it later. It's not something one should do regularly, but when you are after performance, you eventually need it. – Jan Hudec Jul 25 '11 at 16:08
  • @Jan: I do know that you do use explicit allocation and construction under the hood. I just thought that'd be outside the scope of the OP's interest. That's also why I didn't want to add the specifics of `operator new` replacement and allocators to this question. If you want, though, I could do it. – Kerrek SB Jul 25 '11 at 16:21
  • @Bo: But if the constructor throws an exception, I never hit those parts of the code, do I? – Kerrek SB Jul 25 '11 at 16:36
  • @Bo: well, yes, if you tear the example apart, you can run into trouble. But if you enclose the entire example in a try block, it should be fine, non? – Kerrek SB Jul 25 '11 at 16:42
  • @Kerrek - I'm being picky here, but C++0x explicitly says "Initialization of the allocated object is sequenced before the value computation of the *new-expression*", meaning that the value assigned to p isn't available until the initialization is complete. I believe this was the intent in C++03 as well. – Bo Persson Jul 25 '11 at 17:20
  • @Bo: Please do be picky. Do you mean it should be like this: `T * p = operator new(sizeof(T)); try { p = new (p) T; /*...*/ p->~T(); } catch(...){} operator delete(p);`? – Kerrek SB Jul 25 '11 at 17:24
  • @Kerrek - No. :-) The idea is that you should start out with `void* temp = operator new(...` and not assign that to `p` until you have a complete object. (Now the chat police will soon get us). – Bo Persson Jul 25 '11 at 19:02
  • @Bo: Oh OK, I see - I was sweeping the cast to `T*` under the carpet, which should have been a warning sign. OK, I'll edit that! – Kerrek SB Jul 25 '11 at 20:58
2

delete is the same (ish) as free, but has important differences. The most notable difference is that delete will run an objects destructor whereas free won't.

As the comments point out, another very important detail is not mixing malloc/free and new/delete. If you allocate with malloc, use free and similarly if you use new, use delete!

Jeff Foster
  • 43,770
  • 11
  • 86
  • 103
  • It's a undefined behaviour to allocate with `new` and try to free with `free()` or to allocate with `malloc()` and try to free with `delete`. Some implementations will crash if you try that! – Jan Hudec Jul 25 '11 at 13:33
  • Does it work this way, `new`=>(`malloc`)=>`constructor` ; `delete`=>`destructor`=>(`free`) ? Where (`malloc`,`free`) are call "internally/automatically" . Am I rigth? – MrHIDEn Feb 04 '15 at 10:25
0

They are not the same. The delete operator in C++ calls the object's destructor, which, depending on the implementation, should release the memory. The delete function can also be overloaded, where free cannot.

Evan Mulawski
  • 54,662
  • 15
  • 117
  • 144
0

malloc() and free() are not to be used in C++ code because they don't support object semantics. Furthermore, the results of calling free() to release an object that was allocated by new, or of using delete to release memory that was allocated by malloc(), are undefined. The C++ standard doesn't guarantee that the underlying implementation of operator new uses malloc(); in fact, on some implementations malloc() and new use different heaps. Check this link

delete() would delete the entire memory space occupied making it imposible to refer the varaiable once its gets deleted where in free() u could still access it.

nebula
  • 3,932
  • 13
  • 53
  • 82