2016-11-24 2 views
0

Я пытаюсь реализовать класс «Safe Array» для перегрузки операторов. Я успешно перегрузил '[]' оператор, чтобы вернуть правильную ссылку на объект.«SafeArray» Pointer's

Одним из требований моего безопасного массива является то, что указатели на элементы будут поддерживать указатели арифметика, например, учитывая указатель arr[i] я был бы в состоянии получить доступ arr[i+1] по *(&(arr[i]) + 1). Безопасный массив ДОЛЖЕН защищать эту операцию, а в случае попытки получить доступ к объекту вне пределов может вызвать исключение.

Каков наилучший путь для достижения этой цели?

+1

Вы должны реализовать это как часть вашего класса «безопасный итератора». –

+2

Вам нужно будет сделать 'operator []' возвращать объект типа класса, который вы можете перегрузить 'operator &'. –

+1

@thecohenoam: Вы будете использовать те же операторы, которые вы использовали бы для необработанных массивов и указателей. Вы можете использовать оператор преобразования для преобразования в нужное значение. Это не идеально, но в основном работает. –

ответ

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

Вам необходимо создать итераторы для своего класса. По умолчанию вы, вероятно, не должны быть уверены, что & 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 < array.end(), чтобы ваши итераторы не знали об их создателях.