This version of the double-bounded array 
    	       uses unique_ptr instead of shared_ptr.
#ifndef _BOUNDARR_H_
#define _BOUNDARR_H_
/*
 * This class implements an array with user-specified bounds.  Subscripting
 * is done with a at() function, and subscripts are bounds-checked.  This
 * is just like boundarr1.h, except it uses unique ptr, which is more
 * appropriate for this application.
 */
#include <iostream>
#include <string>
#include <stdexcept>
#include <memory>
#include <algorithm>
template <typename T>
class BoundArr {
public:
        // Create a new array of the given dimensions
        BoundArr(int low, int high):
                m_space(new T[high-low+1]), m_low(low), m_high(high) { }
        // Convenience for conventional creation.
        BoundArr(int size): m_space(new T[size]), m_low(0), m_high(size-1) { }
        // Create an array as a copy of another.
        BoundArr(const BoundArr &other) { 
                copyin(other);
        }
        // Perform an array assignment.  Delete our space, then make us a
        // copy of other.
        BoundArr & operator=(const BoundArr &other)
        {
                copyin(other);
                return *this;
        }
        // Find out how large this is.
        int low() const { return m_low; }
        int high() const { return m_high; }
        int size() const { return m_high - m_low + 1; }
        // Subscript the array.  The two versions are allowed, and will
        // be chosen based on the context of use.
        T &at(int subs) { return m_space[offset(subs)]; }
        T const &at(int subs) const { return m_space[offset(subs)]; }
        
        // Print the array to the stream.
        void print(std::ostream &out) const;
private:
        std::unique_ptr<T[]> m_space; // Actual storage space for the array.
        int m_low, m_high;      // Bounds
        // Make us a copy of the other array.  Allocates m_space of
        // the same size, then copies the contents of other.m_size into it,
        // and copies m_size.
        void copyin(const BoundArr<T> &other);
        // Check the bounds, throw if out, then 
        int offset(int sub) const;
};
// Make us a copy of the other array.  Allocates m_space of the same size, then
// copies the contents of other.m_size into it, and copies m_size.
template <typename T>
void BoundArr<T>::copyin(const BoundArr<T> &other)
{
        // Replace any existing space with a new block
        // having the same size and content as other.
        m_space = std::make_unique<T[]>(other.size());
        m_low = other.m_low;
        m_high = other.m_high;
        for(int i = 0; i < size(); ++i) m_space[i] = other.m_space[i];
}
// Check that the sub is in range, and throw if it is not.  Otherwise,
// return the sub adjusted to an offset for subscripting the base array.
template <typename T>
int BoundArr<T>::offset(int sub) const
{
        if(sub < m_low || m_high < sub)
                throw std::range_error("Bounds: sub " + std::to_string(sub) +
                                       " outside " + std::to_string(m_low) +
                                       ".." + std::to_string(m_high));
        return sub - m_low;
}
// Array printer
template <typename T>
void BoundArr<T>::print(std::ostream &out) const
{
        out << "<" << m_low << "|";
        for(int n = 0; n < size(); ++n) {
                out << " " << m_space[n];
        }
        out << " |" << m_high << ">";
}
// This exports the printing function to standard streams by defining
// the meaning of << on a stream and a BoundArr to be running the print
// method on the array to the stream.
template <typename T>
inline std::ostream & operator<<(std::ostream &strm, const BoundArr<T> &arr) 
{
        arr.print(strm);
        return strm;
}
#endif