【问题标题】:"SafeArray" Pointer's“SafeArray”指针
【发布时间】:2016-11-24 23:44:15
【问题描述】:

我正在尝试实现一个“安全数组”类来练习运算符重载。我已成功重载 '[]' 运算符以返回正确的对象引用。

我的安全数组的一个要求是指向项目的指针将支持指针算法,例如,给定一个指向arr[i] 的指针,我将能够通过*(&(arr[i]) + 1) 访问arr[i+1]。安全数组也必须保护此操作,并且在尝试访问越界对象的情况下将引发异常。

实现这一目标的最佳方法是什么?

【问题讨论】:

  • 您需要将其作为“安全迭代器”类的一部分来实现。
  • 你需要让operator[]返回一个可以重载operator&的类类型的对象。
  • @thecohenoam:您将使用与原始数组和指针相同的运算符。您可以使用转换运算符转换为您需要的值。它并不完美,但大多数情况下都有效。

标签: c++ templates pointers operator-overloading


【解决方案1】:

您的要求有点棘手,但可以通过实现一些代理对象来实现,例如:

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];
}

【讨论】:

    【解决方案2】:

    您需要为您的类创建迭代器。默认情况下,您可能不应该确保 &arr[i] + 1 是安全的,因为这将是地狱(而不是返回值,您必须返回某种特殊类来保存具有某种重载的值用于指针访问,然后重载以进行添加)。

    STL 处理安全性的方式是让您通过使用诸如 arr.at(i) 之类的成员来获取迭代器,这是一个包含指向任何数据类型的指针的类,但还具有一些额外的功能确保迭代器操作的一定程度的安全性。

    class Array
    {
        struct Iterator
        {
            Iterator( Array* array, TYPE* ptr ) : m_ptr( ptr ) {}
            ...
            Iterator operator +( int i ){ 
                if( (m_ptr + i) < m_arr->end() ) 
                    return Iterator( m_arr, m_ptr + i ); 
            }
        };
        ...
        Iterator at( unsigned int i ) {
            if( i < m_size )
                return Iterator( this, m_array + i );
        }
    }
    

    请注意,迭代器有一个指向原始数组类的指针。如果您希望迭代器不会像您要求的那样越界,这是必要的,但 STL 迭代器不能以这种方式工作。相反,他们让您检查 iterator &lt; array.end(),这样您的迭代器就不需要知道他们的创建者。

    【讨论】:

      猜你喜欢
      • 2015-11-03
      • 2012-08-03
      • 2012-09-06
      • 2019-06-28
      • 2016-02-24
      • 2014-05-14
      • 2014-10-31
      • 2019-06-18
      • 1970-01-01
      相关资源
      最近更新 更多