9

I know how they are different syntactically, and that C++ uses new, and C uses malloc. But how do they work, in a high-level explanation?

See What is the difference between new/delete and malloc/free?

Community
  • 1
  • 1
Joel
  • 15,166
  • 16
  • 39
  • 31
  • 1
    I don't think this is a duplicate. I think Joel is asking how new/malloc allocate memory and if there is a difference in how they are implemented. This is not the same as how they behave to users. – Jay Conrod Dec 13 '08 at 23:18
  • @Jay: See Joel's comment to @litb's response. – Robert Gamble Dec 13 '08 at 23:33

5 Answers5

10

I'm just going to direct you to this answer: What is the difference between new/delete and malloc/free? . Martin provided an excellent overview. Quick overview on how they work (without diving into how you could overload them as member functions):

new-expression and allocation

  1. The code contains a new-expression supplying the type-id.
  2. The compiler will look into whether the type overloads the operator new with an allocation function.
  3. If it finds an overload of an operator new allocation function, that one is called using the arguments given to new and sizeof(TypeId) as its first argument:

Sample:

new (a, b, c) TypeId;

// the function called by the compiler has to have the following signature:
operator new(std::size_t size, TypeOfA a, TypeOfB b, TypeOf C c);
  1. if operator new fails to allocate storage, it can call new_handler, and hope it makes place. If there still is not enough place, new has to throw std::bad_alloc or derived from it. An allocator that has throw() (no-throw guarantee), it shall return a null-pointer in that case.
  2. The C++ runtime environment will create an object of the type given by the type-id in the memory returned by the allocation function.

There are a few special allocation functions given special names:

  • no-throw new. That takes a nothrow_t as second argument. A new-expression of the form like the following will call an allocation function taking only std::size_t and nothrow_t:

Example:

new (std::nothrow) TypeId;
  • placement new. That takes a void* pointer as first argument, and instead of returning a newly allocated memory address, it returns that argument. It is used to create an object at a given address. Standard containers use that to preallocate space, but only create objects when needed, later.

Code:

// the following function is defined implicitly in the standard library
void * operator(std::size_t size, void * ptr) throw() {
    return ptr;
}

If the allocation function returns storage, and the the constructor of the object created by the runtime throws, then the operator delete is called automatically. In case a form of new was used that takes additional parameters, like

new (a, b, c) TypeId;

Then the operator delete that takes those parameters is called. That operator delete version is only called if the deletion is done because the constructor of the object did throw. If you call delete yourself, then the compiler will use the normal operator delete function taking only a void* pointer:

int * a = new int;
=> void * operator new(std::size_t size) throw(std::bad_alloc);
delete a;
=> void operator delete(void * ptr) throw();

TypeWhosCtorThrows * a = new ("argument") TypeWhosCtorThrows;
=> void * operator new(std::size_t size, char const* arg1) throw(std::bad_alloc);
=> void operator delete(void * ptr, char const* arg1) throw();

TypeWhosCtorDoesntThrow * a = new ("argument") TypeWhosCtorDoesntThrow;
=> void * operator new(std::size_t size, char const* arg1) throw(std::bad_alloc);
delete a;
=> void operator delete(void * ptr) throw();

new-expression and arrays

If you do

new (possible_arguments) TypeId[N];

The compiler is using the operator new[] functions instead of plain operator new. The operator can be passed a first argument not exactly sizeof(TypeId)*N: The compiler could add some space to store the number of objects created (necassary to be able to call destructors). The Standard puts it this way:

  • new T[5] results in a call of operator new[](sizeof(T)*5+x), and
  • new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f).
Community
  • 1
  • 1
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Maybe I just don't know how to search correctly... – Joel Dec 13 '08 at 22:55
  • I have a question. If I have (ignore possible bugs with vtables and such -- just an example): MyClass *p = malloc(sizeof(MyClass)); MyClass *q = new (p) MyClass(); will p == q always? Will q every be < p? Also, how would I delete this? I would have to manually free(), correct? Thanks! (+1 btw) – strager Dec 30 '08 at 09:21
  • thanks mate. yeah q == p, since that placement new will just return p again from its allocation function. actually thare is no issue with vtables whatsoever, you can create any type like that. boost::variant does it that way (as far as i know), for example, to have one buffer for multiple types. – Johannes Schaub - litb Dec 30 '08 at 12:58
  • you delete it by first calling the ctor q->~MyClass(); manually, and then you can call free(p); to release the buffer. hope this helps, good luck :) – Johannes Schaub - litb Dec 30 '08 at 13:10
  • @litb, Thanks many. This really helps my understanding of C++ internals, coming from a C/asm background. =] – strager Dec 31 '08 at 06:22
2

What new does differently form malloc is the following:

  • It constructs a value in the allocated memory, by calling operator new. This behaviour can be adapted by overloading this operator, either for all types, or just for your class.
  • It calls handler functions if no memory can be allocated. This gives you the opportunity to free the required memory on the fly if you have registered such a handler function beforehand.
  • If that doesn't help (e.g. because you didn't register any function), it throws an exception.

So all in all, new is highly customizable and also does initialization work besides memory allocation. These are the two big differences.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
1

Although malloc/free and new/delete have different behaviors, they both do the same thing at a low level: manage dynamically allocated memory. I'm assuming this is what you're really asking about. On my system, new actually calls malloc internally to perform its allocation, so I'll just talk about malloc.

The actual implementation of malloc and free can vary a lot, since there are many ways to implement memory allocation. Some approaches get better performance, some waste less memory, others are better for debugging. Garbage collected languages may also have completely different ways of doing allocation, but your question was about C/C++.

In general, blocks are allocated from the heap, a large area of memory in your program's address space. The library manages the heap for you, usually using system calls like sbrk or mmap. One approach to allocating blocks from the heap is to maintain a list of free and allocated blocks which stores block sizes and locations. Initially, the list might contain one big block for the whole heap. When a new block is requested, the allocator will select a free block from the list. If the block is too large, it can be split into two blocks (one of the requested size, the other of whatever size is left). When an allocated block is freed, it can be merged with adjacent free blocks, since having one big free block is more useful than several small free blocks. The actual list of blocks can be stored as separate data structures or embedded into the heap.

There are many variations. You might want to keep separate lists of free and allocated blocks. You might get better performance if you have separate areas of the heap for blocks of common sizes or separate lists for those sizes. For instance, when you allocated a 16-byte block, the allocator might have a special list of 16-byte blocks so allocation can be O(1). It may also be advantageous to only deal with block sizes that are powers of 2 (anything else gets rounded up). For instance, the Buddy allocator works this way.

Jay Conrod
  • 28,943
  • 19
  • 98
  • 110
0

"new" does a lot more than malloc. malloc simply allocates the memory - it doesn't even zero it for you. new initialises objects, calls contructors etc. I would suspect that in most implementations new is little more than a thin wrapper around malloc for basic types.

Draemon
  • 33,955
  • 16
  • 77
  • 104
0

In C: malloc allocates a chunk of memory of a size that you provide in an argument, and returns back a pointer to this memory.

The memory is declared on the heap, so make sure to deallocate it when you are finished.

barfoon
  • 27,481
  • 26
  • 92
  • 138