I need to build an inner class iterator to work with a container class FigureOfCircles
#define T Circle
class FigureOfCircles {
private:
Circle* c;
int size;
public:
class Iterator {
protected:
T* t;
public:
explicit Iterator (T* t1 = 0) : t(t1) { }
Iterator (const Iterator& x) : t(x.t) {}
T& operator*() const { return *t; }
T* operator->() const { return t; }
Circle& operator[](const std::size_t& n) { return t[n]; }
Iterator& operator++() { ++t; return *this; }
Iterator operator++(int) { return Iterator(t++); }
Iterator& operator--() { --t; return *this; }
Iterator operator--(int) { return Iterator(t--); }
Iterator operator- (int n) { return Iterator(t - n); }
Iterator operator+ (int n) { return Iterator(t - n); }
Iterator& operator-= (int n) { t -= n; return *this; }
Iterator& operator+= (int n) { t += n; return *this; }
bool operator== (const Iterator& x) const { return t == x.t; }
bool operator!= (const Iterator& x) const { return t != x.t; }
bool operator<= (const Iterator& x) const { return t <= x.t; }
bool operator> (const Iterator& x) const { return t > x.t; }
bool operator>= (const Iterator& x) const { return t >= x.t; }
bool operator< (const Iterator& x) const { return t < x.t; }
friend int operator- (const Iterator& x, const Iterator& y) { return x.t - y.t; }
Iterator& operator= (const Iterator& x) {
if (t == x.t) exit(-6);
t = x.t;
return *this;
}
};
FigureOfCircles (int sz) : size(sz) {
c = new T[size];
for (Iterator i = begin(); i != end(); ++i) *i = input();
}
FigureOfCircles(const FigureOfCircles& f) {
size = f.size;
c = new T[size];
for (Iterator i = begin(); i != end(); ++i) *i = f.c[i - begin()];
}
~FigureOfCircles() { if (c) delete[] c; }
Circle input() {
int size = 1;
Point* arr = new Point[size];
float r, x1, y1;
cout << endl << "Введiть к-сть точок, радiус i координати центру: ";
cin >> size >> r >> x1 >> y1;
for (int i = 0; i < size; i++) {
Point tmp;
cin >> tmp;
if (tmp.GetX() == x1 && tmp.GetY() == y1) exit(-7);
if (pow(tmp.GetX() - x1, 2) + pow(tmp.GetY() - y1, 2) != r * r) exit(-8);
arr[i] = tmp;
}
return Circle(size, r, arr, x1, y1);
}
Iterator begin() { return Iterator(c); }
Iterator end() { return Iterator(c+size); }
};
But I don’t understand what type should T be so that I can use the iterator object? If it is int, then what about
Iterator begin() { return Iterator(c); }
Iterator end() { return Iterator(c+size); }
Note:
FigureOfCircles (int sz) : size(sz) {
c = new T[size];
for (int i = 0; i < size; i++)
c[i].input();
for (Iterator i = begin(); i != end(); ++i) {
*i = T(i-begin());
}
}
...
int main () {
//...
FigureOfCircles f(2);
FigureOfCircles::Iterator i;
for (i = f.begin(); i != f.end(); i++) cout << *i << endl;
}
You have an array of Circles, pointed by c. An iterator should point to elements of this array. The simplest solution is to use a plain pointer. That is, T in your iterator should be just Circle.
If you want to use int (it should be std::ptrdiff_t), your iterator should also keep a pointer to the first element. In this particular example I don't see a reason to do it.
operator- should return the difference between pointers, std::ptrdiff_t, not Circle:
friend std::ptrdiff_t operator-(Iterator x, Iterator y) {
return x.t - y.t;
}
Take Iterator by value. It's just a single pointer, you don't need to take it by const-ref (effectively taking a pointer to a pointer).
Once you have iterators, you can use the standard library algorithms to make copies: instead of
for (Iterator i = begin(); i != end(); ++i) *i = f.c[i - begin()];
you can write
std::copy(f.begin(), f.end(), begin());
I suggest you use std::vector<Circle> instead of Circle*. Then you'll be able to borrow its iterators:
class FigureOfCircles {
private:
std::vector<Circle> c;
public:
std::vector<Circle>::iterator begin() {
c.begin();
}
std::vector<Circle>::iterator end() {
c.end();
}
};
This will also save you from writing a copy constructor and destructor.
While #Evg's answer is valid, it is not clear from your question why would even need to write your own iterator. If, instead of a pair of pointer+length members, you would use an std::vector or std::array - or even std::span which is oblivious to where you get your buffer from - you could use these classes' respective iterators instead of implementing your own.
It is only if you have some special behavior in your FigureOfCircles class - e.g. element skipping, non-standard iteration order and so on - that you really need a custom iterator.
PS - The naming is a bit awkward. If a Figure can only have Circles, then just call the class Figure. If there are Figures of something other than Circles, try: template <typename Element> class Figure { ... } and then you'll use Figure<Circle>.
Related
I'm very very new to vectors and templates. Can't seem to wrap my head around them just yet.
The code is as follows:
template <class T>
class m_vector
{
int m_iNextIndex;
int m_iMaxSize;
T* m_pArray;
public:
m_vector()
{
m_pArray = 0;
init();
}
m_vector(const m_vector<T>& other)
{
m_pArray = 0;
m_iNextIndex = 0;
m_iMaxSize = 0;
*this = other;
}
~m_vector()
{
if (m_pArray != 0)
delete [] m_pArray;
}
void init()
{
m_iMaxSize = VECT_INC_SIZE;
m_pArray = new T[m_iMaxSize];
m_iNextIndex = 0;
}
inline void push_back(const T& item)
{
if (m_iNextIndex >= m_iMaxSize)
{
resize(m_iNextIndex + VECT_INC_SIZE);
m_iNextIndex -= VECT_INC_SIZE;
}
m_pArray[m_iNextIndex] = item;
++m_iNextIndex;
}
void resize(int iNewSize)
{
if (iNewSize >= m_iMaxSize)
{
T* temp = new T[iNewSize];
for (int i = 0; i < m_iNextIndex; ++i)
{
temp[i] = m_pArray[i];
}
delete [] m_pArray;
m_pArray = temp;
m_iMaxSize = iNewSize;
}
m_iNextIndex = iNewSize;
}
};
The push_back is called with Vectors that are (x, y) and rectangles that are (x, y, width, height).
I thought that since the code had "m_pArray[m_iNextIndex] = item" that I could simply add a new function to check that the item is unique before adding it to the vector list. So I coded a routine as follows:
int inline exists(const &item)
{
for(int i = 0; i < m_iMaxSize; i++)
{
if(m_pArray[i] == item)
return 1;
}
return 0;
}
The compiler was non to happy. It reported the following error on the if statement:
“left operand must be a pointer or pointer to class member, or arithmetic”
I'm thinking that I probably need something like:
if (type == vector)
if( (m_pArray[i].x == item.x) ....)
else
if( (m_pArray[i].x == item.x) && (m_pArray[i].width == item.width) )
Am I on the right track?
If so, how do I check the type of item.
Thx, Bill.
The problem is that your Vector or Rectangle are missing a comparison operator e.g.
friend bool operator== (Vector const& lhs, Vector const& rhs){
return lhs.x == rhs.x && lhs.y == rhs.y;
}
But the rest of you code is not good and needs a rewrite. I've rewritten my code to old-old style:
NOTE: DON'T BLINDLY COPY THIS CODE. ITS JUST FOR REFERENCE. TEST BEFORE YOU USE
#define VECT_INC_SIZE 10
// replaced by iterator version
//template< class InputIt, class Size, class OutputIt>
//OutputIt copy_n(InputIt first, Size count, OutputIt result) {
// while (count-- > 0) {
// *result++ = *first++;
// }
// return result;
//}
template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last, OutputIt d_first) {
while (first != last) {
*d_first++ = *first++;
}
return d_first;
}
template<class T>
T exchange(T& obj, T new_value)
{
T old_value = obj;
obj = new_value;
return old_value;
}
template <class T>
class m_vector
{
private:
unsigned int size;
unsigned int capacity;
T* array;
public:
m_vector()
: size(0)
, capacity(VECT_INC_SIZE)
, array(new T[VECT_INC_SIZE])
{}
m_vector(m_vector<T> const& other)
: size(other.size)
, capacity(other.capacity)
, array(new T[other.capacity]) {
//copy_n(other.array, size, array);
copy(other.cbegin(), other.cend(), begin());
}
// rule of 3
m_vector& operator=(m_vector<T> const& other) {
if (&other != this) {
if (other.capacity != capacity){
delete [] exchange(array, new T[other.capacity]);
capacity = other.capacity;
}
size = other.size;
//copy_n(other.array, size, array);
copy(other.cbegin(), other.cend(), begin());
}
return *this;
}
~m_vector() {
if (array != 0) delete [] array;
}
void push_back(T const& item) {
if (size >= capacity) {
reserve(capacity + VECT_INC_SIZE);
}
array[size] = item;
++size;
}
void reserve(unsigned int newCapacity) {
if (size > capacity) {
T* const temp = new T[newCapacity];
//copy_n(array, size, temp);
copy(cbegin(), cend(), temp);
delete [] exchange(array, temp);
capacity = newCapacity;
}
}
bool exists(T const& item) const {
//for(unsigned int i = 0; i < size; ++i) {
// if(array[i] == item) return true;
//}
for(T const* it = cbegin(); it != cend(); ++it) {
if(*it == item) return true;
}
return false;
}
void erase(T const& item) {
T* it = begin();
T* const endIt = end();
while(it != endIt && *it != item) ++it;
if (it == endIt) return;
copy(it + 1, endIt, it);
--size;
}
// iterators
T* begin() { return array; }
T* end() { return array + size; }
T const* cbegin() const { return array; }
T const* cend() const { return array + size; }
};
class Vector {
private:
int x,y;
public:
Vector() : x(0), y(0) {}
Vector(int x, int y) : x(x), y(y) {}
friend bool operator== (Vector const& lhs, Vector const& rhs){
return lhs.x == rhs.x && lhs.y == rhs.y;
}
friend bool operator!= (Vector const& lhs, Vector const& rhs){
return !(lhs==rhs);
}
};
#include <cstdio>
void VectorInM_Vector(m_vector<Vector> const& vec, Vector const& item) {
if (vec.exists(item)) printf("Vector found in vector\n");
else printf("Vector not found in vector\n");
}
int main(){
m_vector<Vector> vec;
vec.push_back(Vector(1,1));
VectorInM_Vector(vec, Vector(1,1));
m_vector<Vector> vec2(vec);
vec.erase(Vector(1,1));
VectorInM_Vector(vec, Vector(1,1));
VectorInM_Vector(vec2, Vector(1,1));
vec2 = vec;
VectorInM_Vector(vec2, Vector(1,1));
}
on compiler explorer/godbolt
I want to construct a class of an array whose size is not known,
i want to make objects of array whose size would be initialized at the time when i would create an object(runtime)
class array_class{
public:
int size_of_array;
int arr[size_of_array];
array_class(int p_size_of_array){ //constructor
this->size_of_array=p_size_of_array;
}
};
it say's error of invalid use of non static data member, what wrong am i doing(what should i have known)?.
You can't have something like
void foo(int n)
{
int vals[n];
}
in C++.
The thing is called variable-length array and it's supported in C99.
By the way, it is the only thing I know which is supported in C99 and not supported in C++17 :).
std::vector is a nice alternative.
If you know the size of an array at the compile time, you may use std::array.
I want to construct a class of an array whose size is not known
(what should i have known)?
You should have known that is not not possible in C++. The size of all classes is compile time constant.
i want to make objects of array whose size would be initialized at the time when i would create an object(runtime)
You need to allocate the array dynamically.
A simple solution:
struct array_class {
std::vector<int> arr;
array_class(int p_size_of_array) : arr(p_size_of_array) {}
};
#eerorika and #Nestor have good answers. To add to them here is a simple implementation of a vector i did some time ago you can take as a reference.
As you will see a basic way to have a variable length data structure, is to delete the underlying array and create a larger one if more or less memory is needed.
#pragma once
#include <ostream>
#include <string>
#include <initializer_list>
#include <stdexcept>
static constexpr size_t min_sz = 5;
template<typename T>
class Vector
{
public:
class ConstIterator;
class Iterator;
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type &;
using pointer = value_type *;
using const_pointer = const value_type *;
using iterator = Vector::Iterator;
using const_iterator = Vector::ConstIterator;
/// constructors, destructor, assign
Vector()
{
allocEmpty(min_sz);
}
Vector(Vector<value_type> &vec)
{
allocEmpty(vec.max_sz);
for (size_type i = 0; i < vec.sz; ++i)
values[i] = vec.values[i];
sz = vec.sz;
}
Vector(size_type size)
{
allocEmpty(size);
}
Vector(const std::initializer_list<value_type> &list)
{
allocEmpty(list.size());
size_type i = 0;
for (const auto &val : list)
{
values[i] = val;
++i;
}
sz = list.size();
}
~Vector()
{
delete[] values;
}
Vector &operator=(const Vector &other)
{
reserve(other.sz);
for (size_type i = 0; i < other.sz; ++i)
values[i] = other.values[i];
sz = other.sz;
return *this;
}
/// element access
reference operator[](size_type position)
{
if (position >= sz)
throw std::out_of_range ("operator[] out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));
return values[position];
}
const_reference operator[](size_type position) const
{
if (position >= sz)
throw std::out_of_range ("operator[] out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));
return values[position];
}
const_reference front() const
{
if (sz == 0)
throw std::out_of_range ("front called on empty container");
return values[0];
}
const_reference back() const
{
if (sz == 0)
throw std::out_of_range ("back called on empty container");
return values[sz - 1];
}
pointer data()
{
if (sz > 0)
return values;
return nullptr;
}
const_pointer data() const
{
if (sz > 0)
return values;
return nullptr;
}
/// capacity
size_type size() const
{
return sz;
}
size_type capacity() const
{
return max_sz;
}
bool empty() const
{
return (sz == 0);
}
void reserve(size_type size)
{
if (size <= min_sz)
return;
value_type *newArray = new value_type[size];
for (size_type i = 0; i < sz; ++i)
newArray[i] = values[i];
delete[] values;
values = newArray;
max_sz = size;
}
void shrink_to_fit()
{
size_type newSize = (sz >= min_sz) ? sz : min_sz;
value_type *newArray = new value_type[newSize];
for (size_type i = 0; i < sz; ++i)
newArray[i] = values[i];
delete[] values;
values = newArray;
max_sz = newSize;
}
/// modifiers
void push_back(const value_type &value)
{
if (sz >= max_sz)
reserve(max_sz * 2);
values[sz] = value;
++sz;
}
void resize(size_type count)
{
reserve(count);
sz = count;
}
void resize(size_type count, const value_type &value)
{
reserve(count);
for (size_type i = sz; i < count; ++i)
values[i] = value;
sz = count;
}
void insert(size_type position, const value_type &value)
{
if (position > sz)
throw std::out_of_range ("insert out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));
if (sz >= max_sz)
reserve(max_sz * 2);
for (size_type i = sz; i > position; --i)
values[i] = values[i - 1];
values[position] = value;
++sz;
}
iterator insert(const_iterator pos, const_reference val)
{
auto diff = pos - begin();
if (diff < 0 || static_cast<size_type>(diff) > sz)
throw std::runtime_error("Iterator out of bounds");
size_type current = static_cast<size_type>(diff);
if (sz >= max_sz)
reserve(max_sz * 2);
for (size_t i = sz; i-->current;)
values[i + 1] = values[i];
values[current] = val;
++sz;
return iterator(values + current);
}
void erase(size_type position)
{
if (position >= sz)
throw std::out_of_range ("erase out of range: sz = " + std::to_string(sz) + " but position = " + std::to_string(position));
for (size_type i = position; i < sz - 1; ++i)
values[i] = values[i + 1];
--sz;
}
iterator erase(const_iterator pos)
{
auto diff = pos - begin();
if (diff < 0 || static_cast<size_type>(diff) >= sz)
throw std::runtime_error("Iterator out of bounds");
size_type current = static_cast<size_type>(diff);
for (size_type i = current; i < sz - 1; ++i)
values[i] = values[i + 1];
--sz;
return iterator(values + current);
}
void pop_back()
{
if (sz == 0)
throw std::out_of_range ("pop_back on empty container");
if (sz > 0) --sz;
}
void clear()
{
sz = 0;
}
/// iterators
iterator begin()
{
if (sz == 0)
return end();
return iterator(values);
}
iterator end()
{
return iterator(values + sz);
}
const_iterator begin() const
{
if (sz == 0)
return end();
return ConstIterator(values);
}
const_iterator end() const
{
return ConstIterator(values + sz);
}
/// private section
private:
void allocEmpty(size_type size)
{
auto newSize = (size > min_sz) ? size : min_sz;
sz = 0;
values = new value_type[newSize];
max_sz = newSize;
}
private:
value_type *values;
size_type sz;
size_type max_sz;
/// iterator implementations
public:
class Iterator
{
public:
using value_type = Vector::value_type;
using reference = Vector::reference;
using pointer = Vector::pointer;
using difference_type = Vector::difference_type;
using iterator_category = std::forward_iterator_tag;
public:
Iterator()
{
ptr = nullptr;
}
Iterator(pointer ptr)
{
this->ptr = ptr;
}
reference operator*() const
{
return *ptr;
}
pointer operator->() const
{
return ptr;
}
iterator& operator++()
{
++ptr;
return *this;
}
iterator operator++(int)
{
iterator it = *this;
++ptr;
return it;
}
iterator operator+ (difference_type difference) const
{
return iterator(ptr + difference);
}
bool operator==(const const_iterator &it) const
{
return it == ptr;
}
bool operator!=(const const_iterator &it) const
{
return it != ptr;
}
operator const_iterator() const
{
return const_iterator(ptr);
}
private:
pointer ptr;
};
class ConstIterator
{
public:
using value_type = Vector::value_type;
using reference = Vector::const_reference;
using pointer = Vector::const_pointer;
using difference_type = Vector::difference_type;
using iterator_category = std::forward_iterator_tag;
public:
ConstIterator()
{
ptr = nullptr;
}
ConstIterator(pointer ptr)
{
this->ptr = ptr;
}
reference operator*() const
{
return *ptr;
}
pointer operator->() const
{
return ptr;
}
const_iterator& operator++()
{
++ptr;
return *this;
}
const_iterator operator++(int)
{
const_iterator it = *this;
++ptr;
return it;
}
bool operator==(const const_iterator &it) const
{
return it.ptr == ptr;
}
bool operator!=(const const_iterator &it) const
{
return it.ptr != ptr;
}
Vector::difference_type operator-(const const_iterator &rop)
{
return ptr - rop.ptr;
}
private:
pointer ptr;
};
};
/// non-member functions
template<typename T>
bool operator==(const Vector<T> &lop, const Vector<T> &rop)
{
if (lop.size() != rop.size()) return false;
for (size_t i = 0; i < lop.size(); ++i)
{
if (lop[i] != rop[i])
return false;
}
return true;
}
template<typename T>
std::ostream& operator<<(std::ostream &out, const Vector<T> &vec)
{
out << '[';
for (size_t i = 0; i < vec.size(); ++i)
{
if (i > 0) out << ", ";
out << vec[i];
}
out << ']';
return out;
}
I'm trying to implement a container in C++ that uses a flat array to store the data but iterates over that data in pairs. Now I could easily change the implementation such that the container holds a vector of std::pair however I want to iterate through pairs starting at element 0 or at element 1.
To illustrate what I want to achieve, if my underlying array looks like:
1,2,3,4,5,6,7,8
I want to define two iterators, one which returns the pairs:
(1,2), (3,4), (5,6), (7,8)
and the second iterator to return the pairs:
(2,3), (4,5), (6,7)
is this possible to do while still allowing the elements of the iterator to be references of the underlying array?
It is possible to write your own iterator, which iterates over the elements. The following question shows some explanations on how that is done:
Custom Iterator in C++.
You can then return the desired values as std::pair and iterate to the next element-pair (by incrementing the counter by 2).
Boost library has got Iterator Adaptor that allows you to wrap other iterator types and change or adapt their functionality. Here's how you could use it for your purpose:
#include <boost/iterator/iterator_adaptor.hpp>
#include <vector>
struct iterator :
public boost::iterator_adaptor<
iterator, // the name of our class, see docs for details
std::vector<int>::iterator, // underlying base iterator
std::pair<int&, int&>, // our value type
boost::forward_traversal_tag // the category you wish to give it
>
{
// need this to convert from vector::iterator to ours
explicit iterator(std::vector<int>::iterator i)
: iterator::iterator_adaptor_(i) {}
value_type operator*()
{
return value_type(
*base_reference(),
*(base_reference()+1)
);
}
};
Example of usage:
std::vector<int> v {1,2,3,4};
iterator it(v.begin());
++it;
(*it).first = 0; // TODO: operator->
(*it).second = 0;
for (int i : v) std::cout << i << ' '; // prints 1 0 0 4
You'll also need to override comparison to properly handle end condition, etc. Hope that helps.
Just thought I'd put in what I actually used in my code. I didn't want to use boost as suggested by #jrok but the type std::pair<int&, int&> in their answer gave me a hint of what was required.
Below is the class that I constructed which uses two iterators. A RepeatIterator that returns pairs starting on even indexes in the underlying data, and a SpacerIterator that returns pairs starting on odd indexes.
class RepeatArray {
typedef std::vector<int> storage_t;
public:
class RepeatIterator {
public:
typedef RepeatIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
RepeatIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
class SpacerIterator {
public:
typedef SpacerIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
SpacerIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
void add(int start, int end) {
positions.push_back(start);
positions.push_back(end);
}
void dump() {
for (auto i : positions) {
std::cout <<i<<",";
}
std::cout <<std::endl;
}
RepeatIterator repeatBegin(){return RepeatIterator(positions.begin());}
RepeatIterator repeatEnd(){return RepeatIterator(positions.end());}
SpacerIterator spacerBegin(){return SpacerIterator(positions.begin() + 1);}
SpacerIterator spacerEnd(){return SpacerIterator(positions.end() - 1);}
protected:
storage_t positions;
};
And then the tesing program compiled using clang++ -std=c++0x -o testRepeatArray RepeatArray.cpp
int main() {
RepeatArray r = RepeatArray();
r.add(1,3);
r.add(7,12);
std::cout<<"original:"<<std::endl;
r.dump();
std::cout << "Testing Repeat iterator:"<<std::endl;
for (RepeatArray::RepeatIterator it2 = r.repeatBegin(); it2 != r.repeatEnd(); ++it2) {
std::cout << (*it2).first <<","<< (*it2).second << std::endl;
}
std::cout << "Testing Spacer iterator:"<<std::endl;
for (RepeatArray::SpacerIterator it3 = r.spacerBegin(); it3 != r.spacerEnd(); ++it3) {
std::cout << (*it3).first <<","<< (*it3).second << std::endl;
}
std::cout<<"Testing modification:"<<std::endl;
RepeatArray::RepeatIterator it = r.repeatBegin();
(*it).first = 0;
(*it).second = 123;
r.dump();
return 0;
}
Below is code for my String class. I want to implement reverse_iterator and rbegin() and rend() methods.
Have pasted code for assign method.
String::reverse_iterator rbegin = str2.rbegin();
String::reverse_iterator rend = str2.rend();
for (String::reverse_iterator b = rbegin; b != rend; ++b) {
cout << *b;
}
class String {//my custom string class
public:
class iterator :public std::iterator<std::random_access_iterator_tag, char> {
public:
iterator() :ch(NULL) {}
iterator(const iterator& it) : ch(it.ch) {}
char& operator*() { return *ch; }
iterator& operator++() {
ch = ch + 1;
return *this;
}
bool operator==(const iterator& rhs) {
return ch == rhs.ch;
}
bool operator!=(const iterator& rhs) {
return ch != rhs.ch;
}
private:
friend class String;
iterator(char* c) :ch(c) {}
char* ch;
};
explicit String();
String(const String& str);
String(const char* s);
~String();
iterator begin();
iterator end();
private:
char* _string;
size_t _length;
size_t _capacity;
};
//iterator to end
String::iterator String::end() {
//return iterator();
if (_length == 0) {
return iterator(_string);
}
else {
return iterator(_string + _length + 1);
}
}
void String::assign(const char* str) {
if (sizeof(str) >= max_size()) {
throw std::bad_alloc("String size is greater than max size");
}
if (_string != NULL) {
delete[] _string;
}
_length = strlen(str);
_capacity = _length < 5 ? 5 : _length;
_string = new char[_capacity + 1];
memset(_string, 0, _capacity + 1);
memcpy(_string, str, _length);
}
int main() {
String str2;
str2.assign("This is assigned");
String::iterator begin = str2.begin();
String::iterator end = str2.end();
//below loop should print "This is assigned" and is working fine
for (String::iterator b = begin; b != end; ++b) {
cout << *b;
}
return 1;
}
Reverse iterators can be implemented in terms of bidirectional iterators:
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
... and then the same for const iterators
However, your forward iterator implementation needs to be bidirectional, meaning that it must also support the -- operator:
iterator& operator--()
{
--ch;
return *this;
}
I'm writing an implementation of Deque as a programming exercise and it's not going too well at all. I'm missing a few key function that are needed to make the test main program I was given function correctly.
Here is my code so far:
#include <vector>
#include <iostream>
#include <cassert>
using namespace std;
template <class T> class DequeIterator;
template <class T>
class Deque {
public:
typedef DequeIterator<T> iterator;
Deque(): vecOne(), vecTwo() { }
Deque(unsigned int size, T& initial): vecOne(size/2, initial), vecTwo(size-(size/2), initial) { }
Deque(Deque<T> & d): vecOne(d.vecOne), vecTwo(d.vecTwo) { }
T & operator[](unsigned int);
T & front();//
T & back();//
bool empty(){ return vecOne.empty() && vecTwo.empty(); }
iterator begin() { return iterator(this,0); }
iterator end() { return iterator(this, size ()); }
void erase(const iterator &);
void erase(const iterator &, const iterator &);
void insert(const iterator &, const T &);
int size() { return vecOne.size() + vecTwo.size(); }
void push_front(const T & value) { vecOne.push_back(value); }
void push_back(const T & value) {vecTwo.push_back(value); }
void pop_front();
void pop_back();
protected:
vector<T> vecOne;
vector<T> vecTwo;
};
template <class T>//
T & Deque<T>::front()//returns the first element in the deque
{
if (vecOne.empty())
return vecTwo.front();
else
return vecOne.back();
}
template <class T>//
T & Deque<T>::back()//returns the last element in the deque
{
if (vecOne.empty())
return vecTwo.back();
else
return vecOne.front();
}
template <class T>//
T & Deque<T>::operator[] (unsigned int index)
{
int n = vecOne.size();
if (index < n)
return vecOne [ (n-1) - index ];
else
return vecTwo [ index - n ];
}
template <class T>//
Deque<T>::iterator DequeIterator<T>::operator ++ (int)
{
Deque<T>::iterator clone(theDeque, index);
index++;
return clone;
}
template <class T>//
void Deque<T>::pop_front()
{
}
template <class T>//
void Deque<T>::pop_back()
{
}
template <class T>//
void Deque<T>::erase (const iterator & itr)
{
int index = itr.index;
int n = vecOne.size();
if (index < n)
vecOne.erase (vecOne.begin() + ((n-1) - index));
else
vecTwo.erase (vecTwo.begin() + (n - index));
}
template <class T>//
void Deque<T>::erase (const iterator &, const iterator &)
{
}
template <class T>//
void Deque<T>::insert(const iterator &, const T &)
{
}
template <class T>
class DequeIterator {
friend class Deque<T>;
typedef DequeIterator<T> iterator;
public:
DequeIterator(): theDeque(0), index(0) { }
DequeIterator(Deque<T> * d, int i): theDeque(d), index(i) { }
DequeIterator(const iterator & d): theDeque(d.theDeque), index(d.index) { }
T & operator*() { return (*theDeque)[index]; }
iterator & operator++(int) { ++index; return *this; }
iterator operator++();
iterator operator--(int) { --index; return *this; }
iterator & operator--();
bool operator==(const iterator & r) { return theDeque == r.theDeque && index == r.index; }
bool operator!=(const iterator & r) { return theDeque == r.theDeque && index != r.index; }
bool operator< (const iterator & r) { return theDeque == r.theDeque && index < r.index; }
T & operator[](unsigned int i) { return (*theDeque) [index + i]; }
iterator operator=(const iterator & r) { theDeque = r.theDeque; index = r.index; }
iterator operator+(int i) { return iterator(theDeque, index + i); }
iterator operator-(int i) { return iterator(theDeque, index - i); }
protected:
Deque<T> * theDeque;
int index;
};
main()
{
Deque<int> d;
d.push_back(10);
d.push_back(20);
assert(d.front() == 10);
assert(d.back() == 20);
d.push_front(1);
d.push_front(2);
d.push_front(3);
assert(d.front() == 3);
assert(d.back() == 20);
d.pop_back();
d.pop_back();
d.pop_back();
assert(d.front() == 3);
assert(d.back() == 2);
d.push_back(1);
d.push_back(0);
Deque<int>::iterator i;
int counter = 3;
for (i = d.begin(); i != d.end(); i++)
assert(*i == counter--);
for (counter = 0; counter < d.size(); counter++)
assert(d[counter] == d.size()-counter-1);
i = d.begin() + 3;
Deque<int>::iterator j(i), k;
k = j = i - 2;
assert(*k == 2);
for (i = d.begin(); not(i == d.end()); ++i)
cout << *i << " ";
cout << endl;
d.erase(d.begin()+3);
//d.erase(d.begin(), d.begin()+2);
assert(d.size() == 1);
assert(d[0] == 1);
Deque<int> c(d);
c.front() = 3;
assert(c.back() == 3);
c.push_front(1);
c.insert(c.begin(), 0);
c.insert(c.begin()+2, 2);
for (i = c.begin(); not(i == c.end()); ++i)
cout << *i << " ";
cout << endl;
for (counter = 0; counter < c.size(); counter++)
assert(c[counter] == counter);
cout << "SUCCESS\n";
}
I was wondering if someone could tell me my function from line 66 is returning:
expected constructor, destructor, or type conversion before 'DequeIterator'
Because I'm not sure what I'm doing wrong in it. Also, if someone would be kind enough to give me an example of the pop_front() function so that I can use it to create the pop_back() function as well, that would be great. Lastly, I have on of the erase functions completed but I am not sure how to go about creating the second one, which basically erases a value within the range of two iterators, it is referenced in line 176.
Any help would be greatly appreciated. Thank you in advance.
As for the error, you probably need a typename before Deque<T>::iterator on that line.
typename Deque<T>::iterator DequeIterator<T>::operator++(int)
I think it is a great programming exercise to implement deque. But a prerequisite is to implement vector and list. deque is one of the most complicated std::containers to implement. You should start with one of the simpler ones (vector and list).
Well, you get the error on line 65 because you return an object of a class that hasn't been defined. You only have the forward declaration (prototype) for class DequeIterator, not the implementation.
void pop_back() {
vecTwo.pop_back();
}
void pop_front() {
vecOne.pop_back();
}