Others have already addressed other issues, so I’ll just look at one point: do you ever want to manually delete an object.
The answer is yes. @DavidSchwartz gave one example, but it is rather unusual. I will give an example that, under the hood of what many C ++ programmers use all the time: std::vector (and std::deque , although it is not used quite like that).
As most people know, std::vector allocates a larger block of memory when / if you add more elements than the current distribution can hold. However, when he does this, he has a memory block that can hold more objects than it currently does in the vector.
To deal with this, what vector does under covers, allocates raw memory through an Allocator object (which, unless you specify otherwise, means that it uses ::operator new ). Then, when you use (for example) push_back to add an element to vector , inside the vector uses placement new to create an element in the (previously) unused part of its memory space.
Now, what happens when / if you erase an element from a vector? It cannot just use delete - which will free the entire block of memory; it must destroy one object in this memory without destroying the others, or freeing any of the memory block that it controls (for example, if you erase 5 elements from a vector and then push_back 5 more elements, this is guaranteed that the vector does not redistribute memory when you do it.
To do this, the vector directly destroys the objects in memory, explicitly calling the destructor, and not using delete .
If perhaps someone else should have written a container using continuous storage something like vector (or some version of this, for example, std::deque really), you will almost certainly want to use the same technique.
Just, for example, consider how you can write code for a circular circular buffer.
#ifndef CBUFFER_H_INC #define CBUFFER_H_INC template <class T> class circular_buffer { T *data; unsigned read_pos; unsigned write_pos; unsigned in_use; const unsigned capacity; public: circular_buffer(unsigned size) : data((T *)operator new(size * sizeof(T))), read_pos(0), write_pos(0), in_use(0), capacity(size) {} void push(T const &t) { // ensure there room in buffer: if (in_use == capacity) pop(); // construct copy of object in-place into buffer new(&data[write_pos++]) T(t); // keep pointer in bounds. write_pos %= capacity; ++in_use; } // return oldest object in queue: T front() { return data[read_pos]; } // remove oldest object from queue: void pop() { // destroy the object: data[read_pos++].~T(); // keep pointer in bounds. read_pos %= capacity; --in_use; } // release the buffer: ~circular_buffer() { operator delete(data); } }; #endif
Unlike standard containers, this directly uses operator new and operator delete . For real use, you probably want to use a dispenser class, but for now it will be more distracting than contributing (IMO, anyway).