我正在尝试实现一个“安全数组”类来练习运算符重载。我成功地重载'[]'运算符以返回正确的对象引用。
我的安全数组的一个要求是指向项目的指针将支持指针算术,例如,给定指向arr[i]
的指针我将能够通过{{1}访问arr[i+1]
}}。安全数组也必须保护此操作,并且在尝试访问越界对象时将抛出异常。
实现这一目标的最佳方法是什么?
答案 0 :(得分: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];
}
答案 1 :(得分:0)
您需要为您的类创建迭代器。默认情况下你可能不应该确保&amp; 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()
,以便您的迭代器不需要知道它们的创建者。