C++: Memory Allocation

Bjarne-stroustrup
 


Show how to explicitly allocate and deallocate blocks of memory in your language. Show access to different types of memory (i.e., heap, stack, shared, foreign) if applicable.

While the C allocation functions are also available in C++, their use is discouraged. Instead, C++ provides new and delete for memory allocation and deallocation. Those function don’t just allocate memory, but also initialize objects. Also, deallocation is coupled with destruction.

#include <string>

int main()
{
	int* p;

	p = new int;    // allocate a single int, uninitialized
	delete p;       // deallocate it

	p = new int(2); // allocate a single int, initialized with 2
	delete p;       // deallocate it

	std::string* p2;

	p2 = new std::string; // allocate a single string, default-initialized
	delete p2;            // deallocate it

	p = new int[10]; // allocate an array of 10 ints, uninitialized
	delete[] p;      // deallocation of arrays must use delete[]

	p2 = new std::string[10]; // allocate an array of 10 strings, default-initialized
	delete[] p2;              // deallocate it
}

Note that memory allocated with C allocation functions (malloc, calloc, realloc) must always be deallocated with free, memory allocated with non-array new must always be deallocated withdelete, and memory allocated with array new must always deallocated with delete[]. Memory allocated with new also cannot be resized with realloc.

Note that use of the array form is seldom a good idea; in most cases, using a standard container (esp. std::vector) is a better idea, because it manages the memory for you, it allows you to define an initial value to set in the array (new[] always default-initializes), and like malloc, but unlike array new, it allows resizing (and unlike realloc, it correctly handles construction/destruction when resizing).

Besides the new expressions shown above, pure memory allocation/deallocation without object initialization/destruction can also be done through operator new:

int main()
{
      void* memory = operator new(20); // allocate 20 bytes of memory
      operator delete(memory);         // deallocate it
}

There’s also a placement form of new, which allows to construct objects at an arbitrary adress (provided it is correctly aligned, and there’s enough memory):

#include <new>

int main()
{
	union
	{
		int alignment_dummy; // make sure the block is correctly aligned for ints
		char data[2*sizeof(int)]; // enough space for 10 ints
	};
	int* p = new(&data) int(3); // construct an int at the beginning of data
	new(p+1) int(5); // construct another int directly following
}

Indeed, code like int* p = new int(3); is roughly (but not exactly) equivalent to the following sequence:

void* memory_for_p = operator new(sizeof(int));
int* p = new(memory_for_p) int(3);

Normally, new throws an exception if the allocation fails. there’s a non-throwing variant which returns a null pointer instead:

#include <new>
 
int* p = new(std::nothrow) int(3);

Note that the nothrow variant does not prevent any exceptions to be thrown from the constructor of an object created with new. It only prevents exceptions due to memory allocation failure.

It is also possible to implement user-defined variations of operator new. One possibility is to define class-based operator new/operator delete:

#include <cstddef>
#include <cstdlib>
#include <new>

class MyClass
{
public:
	void* operator new(std::size_t size)
	{
		void* p = std::malloc(size);
		if (!p) throw std::bad_alloc();
		return p;
	}
	void operator delete(void* p)
	{
		free(p);
	}
};

int main()
{
	MyClass* p = new MyClass; // uses class specific operator new
	delete p;                 // uses class specific operator delete

	int* p2 = new int; // uses default operator new
	delete p2;         // uses default operator delete
}

Another possibility is to define new arguments for placement new syntax, e.g.

class arena { /* ... */ };

void* operator new(std::size_t size, arena& a)
{
	return arena.alloc(size);
}

void operator delete(void* p, arena& a)
{
	arena.dealloc(p);
}

arena whatever(/* ... */);

int* p = new(whatever) int(3); // uses operator new from above to allocate from the arena whatever

Note that there is no placement delete syntax; the placement operator delete is invoked by the compiler only in case the constructor of the newed object throws. Therefore for placement newed object deletion the two steps must be done explicitly:

class MyClass { /*...*/ };

int main()
{
	MyClass* p = new(whatever) MyClass; // allocate memory for myclass from arena and construct a MyClass object there
	// ...
	p->~MyClass(); // explicitly destruct *p
	operator delete(p, whatever); // explicitly deallocate the memory
}

SOURCE

Content is available under GNU Free Documentation License 1.2.