Search code examples
c++dynamic-allocation

Deallocating (and calling a destructor of) a template argument


Context

I'm trying to implement my version of the std::vector template class. The vector contains a dynamic array of the template argument T:

_vec = new T[n];

Obviously T can be any type at all, pointers, classes, primitive types. When one call v.resize(4) on a vector of size 6 it should obviously remove the last 2 elements of the dynamic array (without reallocating the array) following this specification:

If n is smaller than the current container size, the content is reduced to its first n elements, removing those beyond (and destroying them).

By destroying I mean, and I think the std library means, calling the destructor for object or simply deallocating the memory space if it is any other primitive type including pointers.

Question: Is it possible (and if so, how) destroy template elements in a dynamically allocated array without deallocating and reallocating it?

What have I tried? Well, I sincerely don't know where to start:

  • Apparently you shouldn't call a delete on primitive types.
  • You can explicitly call a destructor on an object, but that wouldn't work if T is not an object.
  • I thought of just decreasing the internal _size counter (so that an a future push_back the elements would be overwritten), but that wouldn't immediately call the destructor for the object.

Solution

  • When you are implementing a vector, you probably want to keep the management of the storage and the management of the objects separate.

    Storage is managed using allocator::allocate(size_type n) and allocator::deallocate(pointer p, size_type n), which are typically implemented as return ::operator new(n * sizeof (T)); and ::operator delete(p); respectively.

    These functions allocate and deallocate memory, but do not call constructors or destructors for objects contained in that memory.

    Object lifetimes are managed using allocator::construct(U* p, Args&&... args); and allocator::destroy(U* p);, which are typically implemented as ::new((void *)p) U(std::forward<Args>(args)...); and p->~U() respectively.

    These functions construct and deconstruct objects in preallocated memory, but do not themselves manage the memory.