Why explicit memory management complicates our implementation
Let’s look for a moment at one of the constructors for Vector<T> as written in Chapter 12. For simplicity, we will use the constructor that accepts a number of elements and an initial value for these elements as arguments. If we limit ourselves to the naïve version where elems points to a sequence of T objects and put aside for the moment the more sophisticated version where elems points to a block of memory that holds T objects at the beginning and raw memory at the end, we have the following:
   // naïve version with elems of type T*
   Vector(size_type n, const_reference init)
      : elems{ new value_type[n] }, nelems{ n }, cap{ n } {
      try {
         std::fill(begin(), end(), init);
      } catch (...) {
   &...