Question

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.
Was it helpful?

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.

OTHER TIPS

new T[n] is not what you want, because that will already create n objects of type T, but you only want to allocate memory for up to n objects of type T.

You may want to read up on placement-new syntax and placement-delete syntax. Wikipedia

FredOverflow is right about object allocation.

According your question, all you need to do is just distinguish objects from non-objects (scalars). There is a real code from <xmemory> in Visual Studio 2010 distribution:

template<class _Alloc> inline void _Destroy_range(
  typename _Alloc::pointer _First, typename _Alloc::pointer _Last, _Alloc& _Al);

template<class _Alloc> inline void _Destroy_range(
  typename _Alloc::pointer _First, typename _Alloc::pointer _Last, _Alloc& _Al, 
  _Nonscalar_ptr_iterator_tag);  // Object overload

template<class _Alloc> inline void _Destroy_range(
  typename _Alloc::pointer _First, typename _Alloc::pointer _Last, _Alloc& _Al, 
  _Scalar_ptr_iterator_tag);  // Non-object overload

They use simple dispatching with a special flag, which can be computed using some traits class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top