thecohenoam thecohenoam - 14 days ago 3
C++ Question

"SafeArray" Pointer's

I am trying to implement a "Safe Array" class to practice operators overloading. I had successfully overloaded '[]' operator to return the right object reference.

One of the requirements of my safe array is that the pointers to the items will support pointers arithmetic, for example, given a pointer to

arr[i]
I would be able to access
arr[i+1]
by
*(&(arr[i]) + 1)
. The safe array MUST protect this operation as well, and in case of trying to access an out-of-bounds object will throw an exception.

What is the best way to achieve this goal?

Answer

What you are asking for is a bit tricky, but doable by implementing some proxy objects, eg:

template<typename T>
class SafeArray
{
private:
    T* m_arr;
    size_t m_size;

    T& at(size_t index);
    const T& at(size_t index) const;

public:
    ...

    class Proxy
    {
    private:
        SafeArray<T>& m_sa;
        size_t m_index;

        Proxy(SafeArray<T>& sa, size_t index);

        friend class SafeArray<T>;

    public:
        operator T() const;
        Proxy& operator=(const T &value);

        class Ptr
        {
        private:
            SafeArray<T>& m_sa;
            size_t m_index;

            Ptr(SafeArray<T>& sa, size_t index);

            friend class SafeArray<T>::Proxy;

        public:
            Ptr operator+(size_t rhs);
            Ptr operator-(size_t rhs);
            Ptr& operator++();
            Ptr operator++(int);
            Ptr& operator--();
            Ptr operator--(int);

            Proxy operator*();
        };

        Ptr operator&();
    };

    friend class Proxy;

    Proxy operator[](size_t index);
};

template<typename T>
T& SafeArray<T>::at(size_t index)
{
    if (index >= m_size)
        throw std::out_of_range();
    return m_arr[index];
}

template<typename T>
const T& SafeArray<T>::at(size_t index) const
{
    if (index >= m_size)
        throw std::out_of_range();
    return m_arr[index];
}

template<typename T>
SafeArray<T>::Proxy SafeArray<T>::operator[](size_t index)
{
    return Proxy(*this, index);
}

template<typename T>
SafeArray<T>::Proxy::Proxy(SafeArray<T>& sa, size_t index)
    : m_sa(sa), m_index(index)
{
}

template<typename T>
SafeArray<T>::Proxy::operator T() const
{
    return m_sa.at(m_index);
} 

template<typename T>
SafeArray<T>::Proxy& SafeArray <T>::Proxy::operator=(const T &value)
{
    m_sa.at(m_index) = value;
    return *this;
}

template<typename T>
SafeArray<T>::Proxy::Ptr SafeArray<T>::Proxy::operator&()
{
    return Ptr(m_sa, m_index);
}

template<typename T>
SafeArray<T>::Proxy::Ptr::Ptr(SafeArray<T>& sa, size_t index)
    : m_sa(sa), m_index(index)
{
}

template<typename T>
SafeArray<T>::Proxy::Ptr SafeArray<T>::Proxy::Ptr::operator+(size_t rhs)
{
    return Ptr(m_sa, m_index + rhs);
}

template<typename T>
SafeArray<T>::Proxy::Ptr SafeArray<T>::Proxy::Ptr::operator-(size_t rhs)
{
    return Ptr(m_sa, m_index - rhs);
}

template<typename T>
SafeArray<T>::Proxy::Ptr& SafeArray<T>::Proxy::Ptr::operator++()
{
    ++m_index;
    return *this;
}

template<typename T>
SafeArray<T>::Proxy::Ptr SafeArray<T>::Proxy::Ptr::operator++(int)
{
     retrurn Ptr(m_sa, m_index++);
}

template<typename T>
SafeArray<T>::Proxy::Ptr& SafeArray<T>::Proxy::Ptr::operator--()
{
     --m_index;
     return *this;
}

template<typename T>
SafeArray<T>::Proxy::Ptr SafeArray<T>::Proxy::Ptr::operator--(int)
{
    return Ptr(m_sa, m_index--);
}

template<typename T>
SafeArray<T>::Proxy SafeArray<T>::Proxy::Ptr::operator*()
{
    return m_sa[m_index];
}