Array.h
#pragma once
#include<stdexcept>
using std::out_of_range;
#include<iostream>
using std::ostream;
/* A fixed-size array class with an iterator
* This would need some additional functions and a const iterator to be const-correct
*/
template<class T>
class Array
{
public:
Array(const unsigned int sz) : m_size(sz), m_items(new T[m_size]) {}
Array(const Array& a)
{
m_size = a.m_size;
m_items = new T[a.m_size];
for(unsigned int i = 0; i < m_size; i++)
m_items[i] = a.m_items[i];
}
~Array()
{
delete [] m_items;
}
Array& operator=(const Array a)
{
using std::swap; // copy-and-swap idiom
swap(a.m_size, m_size);
swap(a.m_items, m_items);
return *this;
}
// Accessors
unsigned int size() const { return m_size; }
T& operator[](const unsigned int idx)
{
if(idx >= m_size)
throw out_of_range("idx too large");
return m_items[idx];
}
friend ostream& operator<<(ostream& out, Array& a)
{
out << "[";
for(auto elem : a)
out << elem << ",";
out << "\b]"; // this is cheating
return out;
}
/* Iterator
* This can be iterated forward and backwards, either one at a time or in jumps.
* You could also implement this as a pointer right into the Array's member,
* but that would require some extra stuff to keep you from indexing out of bounds.
* (Here, we just rely on the Array to stop us from doing that.)
*/
class iterator
{
public:
iterator(Array* a, unsigned int idx): m_array(a), m_idx(idx) {}
T& operator*() { return (*m_array)[m_idx]; }
T& operator->() { return (*m_array)[m_idx]; } // for arrays of structs/classes
iterator& operator++()
{
m_idx++;
return *this;
}
iterator operator++(int)
{
iterator temp = *this;
m_idx++;
return temp;
}
iterator& operator+=(const unsigned int inc)
{
m_idx += inc;
return *this;
}
iterator& operator--()
{
m_idx--;
return *this;
}
iterator operator--(int)
{
iterator temp = *this;
m_idx--;
return temp;
}
iterator& operator-=(const unsigned int dec)
{
m_idx -= dec;
return *this;
}
friend bool operator==(const iterator& a, const iterator& b)
{
return a.m_array == b.m_array && a.m_idx == b.m_idx;
}
friend bool operator!=(const iterator& a, const iterator& b)
{
return !(a == b);
}
private:
Array* m_array;
unsigned int m_idx;
};
// If you implement these two functions, range-based for loops Just Work (TM)
// (that is, std::begin() and std::end() will know what to do)
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, m_size); }
private:
unsigned int m_size;
T* m_items;
};