Automatically create iterator from class that implements operator[] - c++

Suppose I have a class that implements operator[], e.g.:
class Array {
public:
Array(size_t s) : data(new int[s]) {}
~Array() { delete[] data; }
int& operator[](size_t index) {
return data[index];
}
private:
int* data;
};
Is there a way to create a random access iterator from the class without having to manually create the iterator class and all its methods? I could manually define the class as follows:
class ArrayIterator : public std::iterator<std::random_access_iterator_tag, int> {
public:
ArrayIterator(Array& a) : arr(a), index(0) {}
reference operator[](difference_type i) {
return arr[index + i];
}
ArrayIterator& operator+=(difference_type i) {
index += i;
return *this;
}
bool operator==(const ArrayIterator& rhs) {
return &arr == &rhs.arr && index == rhs.index;
}
// More methods here...
private:
Array& arr;
difference_type index;
};
But doing so is time consuming since there are so many methods to implement, and each iterator for a class with operator[] would have the exact same logic. It seems it would be possible for the compiler to do this automatically, so is there a way to avoid implementing the entire iterator?

Is there a way to create a random access iterator from the class without having to manually create the iterator class and all its methods?
The simplest way to create a random-access iterator is to just use a raw pointer, which satisfies all of the requirements of the RandomAccessIterator concept (the STL even provides a default template specialization of std::iterator_traits for raw pointers), eg:
class Array {
public:
Array(size_t s) : data(new int[s]), dataSize(s) {}
~Array() { delete[] data; }
int& operator[](size_t index) {
return data[index];
}
size_t size() const { return dataSize; }
int* begin() { return data; }
int* end() { return data+dataSize; }
const int* cbegin() const { return data; }
const int* cend() const { return data+dataSize; }
private:
int* data;
size_t dataSize;
};

Implementing the random access operator by using operator[] may work, but it can be very inefficient and that's why compilers dont do that automatically. Just imagine adding operator[] to a class like std::list, where "going to element i" may take up to i steps. Incrementing an iterator based on operator[] would then have complexity O(n), where n is the size of the list. However, users of random access iterators, expect a certain efficiency, typically O(1).

Related

Making a class iterable with iteration order depending on class implementation

I have a type that has two different implementations, using different data structures. One stores its data in a std::vector<std::unique_ptr<Data>>, the other in a 2D array Data***.
The elements are stored in a specific order, meaning that their position in the vector or 2D array matters. As such, when wanting to iterate over all data in my class, my for loops are dependent on the implementation, being basically one of the following:
for(auto& data : myClass->dataVector) { do Stuff }
for(int x = 0; x < myClass->xVals; x++) {
for(int y = 0; y < myClass->yVals; y++ {
do Stuff with myClass->dataArr[x][y]
}
}
Since the two version of my class share similarities, I want to have a proper parent class that is implemented by two inheriting classes, hopefully in a way that I can iterate over my data by simply doing something such as:
for(auto& data : myClass) { doStuff }
(notice how myClass acts as if it was a collection itself, even if it actually is just a container of a collection)
where the way and order in which this iteration works obviously depends on the implementation of the class.
How do make my class iterable in such a manner?
Lets assume you have a base with all the data, and two derived classes with traversal behavior:
class Base {
public:
std::vector<...> dataVector;
int xVals;
int yVals;
Data** dataArr;
};
Defining .begin() and .end() makes a class iterable with for_each. A simple forwarding to the vector iterators is enough for the first case:
class DerivedA : private Base {
public:
auto begin() { return this->dataVector.begin(); }
auto begin() const { return this->dataVector.begin(); }
auto end() { return this->dataVector.end(); }
auto end() const { return this->dataVector.end(); }
}
For the Data** case you will have to define a custom iterator:
class iterator {
public:
using value_type = Data;
using difference_type = std::ptrdiff_t;
using reference = Data&;
using pointer = Data*;
using iterator_category = std::forward_iterator_tag;
iterator() : m_base(), m_idx(0) { }
iterator(Base* b, std::size_t idx) : m_base(b), m_idx(idx) { }
reference operator*() const { return m_base->dataArr[m_idx / m_base->yVals][m_idx % m_base->y_vals]; }
pointer operator->() const { return &**this; }
friend iterator& operator++(iterator& rhs) { ++rhs.m_idx; return rhs; }
friend iterator operator++(iterator& lhs, int) { auto cp = lhs; ++lhs; return cp; }
friend bool operator==(iterator lhs, iterator rhs) { return lhs.m_idx == rhs.m_idx; }
friend bool operator!=(iterator lhs, iterator rhs) { return !(lhs == rhs); }
private:
Base* m_base;
std::size_t m_idx;
};
class const_iterator {
// equivalent but const. (reference = const Data& and pointer = const Data*)
// Make sure iterator is convertible to const_iterator.
};
class DerivedB : private Base {
iterator begin() { return { this, 0 }; }
const_iterator begin() const { return { this, 0 }; }
iterator end() { return { this, this->xVals*this->yVals }; }
const_iterator end() const { return { this, this->xVals*this->yVals }; }
};

How can I implement random access iterators for my container?

This is the header file for the container including a try to implement random access iterators :
using namespace std;
template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
public:
Element** data;
unsigned int curr_size;
unsigned int max_size;
int* availability_array;
explicit UniqueArray(unsigned int size);
UniqueArray(const UniqueArray& other);
~UniqueArray();
// UniqueArray& operator=(const UniqueArray&) = delete;
unsigned int insert(const Element& element);
bool getIndex(const Element& element, unsigned int& index) const;
const Element* operator[] (const Element& element) const;
bool remove(const Element& element);
unsigned int getCount() const;
unsigned int getSize() const;
class Filter {
public:
virtual bool operator() (const Element&) const = 0;
};
UniqueArray filter(const Filter& f) const;
class UniqueArrayIsFullException{};
typedef Element ua_iterator;
typedef const Element ua_const_iterator;
ua_iterator begin(){
return **data;
}
ua_const_iterator begin() const {
return **data;
}
ua_iterator end(){
return *(*data + max_size);
}
ua_const_iterator end() const {
return *(*data + max_size);
}
};
A summary of the errors I get :
error: no match for ‘operator++’
error: no match for ‘operator*’
error: no type named ‘value_type’ in ‘struct std::iterator_traits<MtmParkingLot::Vehicle>
error: no match for ‘operator!=’
error: no match for ‘operator-’
On my implementation Element gets Vehicle and all these missing operators refer to Vehicle
I'm not quite sure on how to work on these errors because for example substracting Vehicles makes no sense..
If you want an iterator to return a reference to an object when it is dereferenced, you have to define a special Iterator class to do it. With boost::indirect_iterator this is pretty simple:
#include <boost/iterator/indirect_iterator.hpp>
template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
// ...
auto begin() {
return boost::indirect_iterator<Element**, Element>(data_);
}
auto end() {
return boost::indirect_iterator<Element**, Element>(data_ + curr_size);
}
};
Simple demo
If you want to code it yourself, the idea is:
template<class Element>
class UniqueArray {
public:
//...
class Iterator {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = Element;
using reference = Element&;
// ...
Iterator(Element** d) : data(d) { }
reference operator*() {
return **data;
}
Iterator& operator++() {
++data;
return *this;
}
friend bool operator!=(Iterator it1, Iterator it2) {
return it1.data != it2.data;
}
// ...
private:
Element** data;
};
Iterator begin() {
return Iterator(data);
}
Iterator end() {
return Iterator(data + curr_size);
}
};
Note, the full random access iterator requires implementation of many other member and non-member functions. You might want to make it a forward iterator to simplify things a little bit.
Simple demo
If you write that without the type aliases, you get definitions like
Element begin(){
return **data;
}
and use like
UniqueArray<Vehicle>::ua_iterator it = something.begin();
it++;
becomes
Vehicle it = something.begin();
it++;
which makes the cause of the errors more obvious - you're trying to apply iterator operations to your element type.
If you're fine with iteration producing Element*, the simple solution is
typedef Element** ua_iterator;
ua_iterator begin(){
return data;
}
ua_iterator end(){
return data + curr_size;
}
and similar for the const versions.
Then you could write
UniqueArray<Vehicle>::ua_iterator it = something.begin();
Vehicle* v = *it;
If you want iteration to produce Element&, you need to write an iterator class with the appropriate overloads and traits.
It's not very difficult, but it gets tedious.

avoiding dangling reference in array subscription operator

How to avoid dangling reference in array subscription operator in some vector implementation below? If realloc changes the pointer then references previously obtained from operator[] are no longer valid. I cannot use new/delete for this. I have to use malloc/realloc/free.
template <class T>
class Vector
{
public:
typedef size_t size_type_;
...
T& operator[] (const size_type_);
void push_back (const T&);
...
private:
const size_type_ page_size_;
size_type_ size_;
size_type_ capacity_;
T* buffer_;
};
template<class T>
inline
T&
some_namespace::Vector<T>::operator[] (const size_type_ index)
{
ASSERT(index < size_);
return buffer_[index];
}
template<class T>
inline
void
some_namespace::Vector<T>::push_back(const T& val)
{
if (size_ >= capacity_)
{
capacity_ += page_size_;
T* temp = (T*)(realloc(buffer_, capacity_*sizeof(T)));
if (temp != NULL)
{
buffer_ = temp;
}
else
{
free(buffer_);
throw some_namespace::UnexpectedEvent();
}
}
buffer_[size_++] = val;
}
By the way, the source of dangling reference in the code was this:
v_.push_back(v_[id]);
where v_ is an instance of Vector. To guard against this the new push_back is:
template<class T>
inline
void
some_namespace::Vector<T>::push_back(const T& val)
{
if (size_ >= capacity_)
{
const T val_temp = val; // copy val since it may come from the buffer_
capacity_ += page_size_;
T* temp = (T*)(realloc(buffer_, capacity_*sizeof(T)));
if (temp != NULL)
{
buffer_ = temp;
}
else
{
free(buffer_);
throw some_namespace::UnexpectedEvent();
}
buffer_[size_++] = val_temp;
}
else
{
buffer_[size_++] = val;
}
}
There are basically three things you can do:
Accept it as is and document it. This is what the STL does and it's actually quite reasonable.
Don't return a reference, return a copy. Of course, this means you can't assign to the vector's element anymore (v[42] = "Hello"). In that case you want a single operator[] which is marked const.
Return a proxy object which stores a reference to the vector itself and the index. You add an assignment to the proxy from const T& to allow writing to the vector's element and you need to provide some way to access/read the value, most likely an implicit operator const T&. Since the proxy object asks the vector on each access for the current position of the element, this works even if the vector changed the location of those elements between calls. Just be careful with multi-threading.
Here's a sketch for the proxy, untested and incomplete:
template<typename T> class Vector
{
private:
// ...
// internal access to the elements
T& ref( const size_type_ i );
const T& ref( const size_type_ i ) const;
class Proxy
{
private:
// store a reference to a vector and the index
Vector& v_;
size_type_ i_;
// only the vector (our friend) is allowed to create a Proxy
Proxy( Vector& v, size_type_ i ) : v_(v), i_(i) {}
friend class Vector;
public:
// the user that receives a Proxy can write/assign values to it...
Proxy& operator=( const T& v ) { v_.ref(i_) = v; return *this; }
// ...or the Proxy can convert itself in a value for reading
operator const T&() const { return v_.ref(i_); }
};
// the Proxy needs access to the above internal element accessors
friend class Proxy;
public:
// and now we return a Proxy for v[i]
Proxy operator[]( const size_type_ i )
{
return Proxy( *this, i );
}
};
Note that the above is incomplete and the whole technique has some drawbacks. The most significant problem is that the Proxy "leaks" in the API and therefore some use cases are not met. You need to adapt the technique to your environment and see if it fits.

A custom Vector and Matrix class in C++ and operator[]

I have a vector class in C++ that relies on raw pointer. I dont use std::vector as I need to create vector objects from raw pointers for specifal cases. Here is very simple example of my class:
template <typename T>
class Vector
{ ...
private:
T * m_data; int m_size; bool dontFree; ...
public:
Vector(T *const ptr, int size) { m_data = ptr; m_size = size; dontFree = true; }
Vector(int size, T val) { ... dontFree = false; }
~Vector(): { if(!dontFree) delete [] m_data; }
T& operator[](const size_type index);
};
Similarly I have the matrix data type that also stores data in raw pointer and can use vector to support [][] as it is not allowed in C++, something like:
template<typename T>
class Matrix
{
private:
T * m_data; ...
public:
...
Vector<T>& operator[](const int rowIndex)
{
return Vector<T>(&m_data[rowSize * rowIndex], rowSize);
}
}
How could I do efficiently implement operator[] for matrix returing a Vector so that I can write code, something follow:
Matrix<int> m(5,5);
m[1][1] = 10;
int temp = m[1][2];
Please suggest considering the overhead of copy constructor etc.
Create a proxy class that overloads operator[] that you can give access to your matrix's array. Something like this:
template<typename T>
class Proxy
{
public:
Proxy(T * tp)
:rowStart(tp)
{}
T & operator[](const int columnIndex)
{
return rowStart[columnIndex];
}
private:
T * rowStart;
};
Then your Matrix class' operator[] can return one of these, like this:
Proxy<T> operator[](const int rowIndex)
{
return Proxy<T>(m_data + rowSize * rowIndex);
}
It's not complete of course, but it should get you started.
You should return vector by value to make your code correct. Also you can write a small proxy if your vector does a lot of work inside a copy constructor.
If you implement your operator[] as inline method (e.g. don't move implementation to cpp) then good compiler should optimize your code and eliminate unnecessary copying.
But if you are crazy about performance then you can return a raw pointer from the operator:
...
T* operator[](const int rowIndex)
{
return m_data + rowSize * rowIndex;
}
...
int temp = m[1][2];
But is a dangerous approach!
The recommendation when implementing multidimensional matrices is not to overload operator[], but rather overload operator() with multiple dimensions. There are a few reasons that you can read in the C++ FAQ lite
template <typename T>
class Matrix {
public:
typedef std::size_t size_type;
typedef T & reference;
typedef T const & const_reference;
const_reference operator()( size_type x, size_type y ) const;
reference operator()( size_type x, size_type y );
};

Random access priority queue

Continuing List to priority queue
I'm implementing a improved priority_queue with random access.
template <class T, class Container = std::vector<T> >
class Heap {
public:
Heap() {}
Heap(const Container& container) {
container_ = container;
std::make_heap(container_.begin(), container_.end());
}
Heap<T, Container>& operator=(const Heap<T, Container>& heap) {
if (this != &heap)
container_ = heap.container_;
return *this;
}
void push(const T& x) {
container_.push_back(x);
std::push_heap(container_.begin(), container_.end());
}
void pop() {
std::pop_heap(container_.begin(), container_.end());
container_.pop_back();
}
const T& top() {
return container_.front();
}
const Container& getContainer() const {
return container_;
}
T& operator[](size_t n) {
return container_[n];
}
typename Container::const_iterator begin() const {
return container_.begin();
}
typename Container::const_iterator end() const {
return container_.end();
}
size_t size() const {
return container_.size();
}
T& base() {
return container_.back();
}
Container::iterator erase(Container::iterator position) {
return container_.erase(position);
}
private:
Container container_;
};
Am I taking the right way?
Fixed the unary constructor.
Improved code.
Doesn't look that great to me:
The unary constructor should take argument by const reference.
The assignment operator doesn't check for self-assignment.
The getContainer() method shows a lack of clarity in the interface - why would you simply expose the implementation detail like that?
Most importantly: why do you want a "random access priority queue"?
Your pop() method can violate the heap ordering. Use pop_heap() instead of pop_back(). I can't seem to find any other bug right now.
You can easily test such an implementation by pushing in a random integers and pop() them one by one. You should get them back in sorted order. This is known as heap sort.
Suggestions:
Instead of returning a ref to the container you could implement an const iterator to this class.
Note that you should not change the key of the randomly accessed element because it may destroy the heap structure. If you need such functionality you should implement a change_key function which would change the key safely and maintain the heap ordering.