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
Related
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>.
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 would like to dump the content inside the object tmp_np which is a UllmanSet which if you know a key then you know the position and if you know the position , you know the key. Is there a standard C++ container that's similar to the Ullmanset. Ullmanset 's index starts at 0 and Ullmanset1's index start at 1.
and also dump the content of frontierq which is a PriorityQ class.
UllmanSet tmp_np;
template<unsigned B>
class BasedUllmanSet
{
size_t n;
std::vector<int> key;
BasedVector<unsigned, B> pos;
public:
BasedUllmanSet()
: n(0)
{}
BasedUllmanSet(size_t cap)
: n(0), key(cap), pos(cap)
{}
size_t capacity() const { return key.size(); }
size_t size() const { return n; }
bool empty() const { return n == 0; }
void clear() { n = 0; }
void resize(size_t cap)
{
key.resize(cap);
pos.resize(cap);
n = 0;
}
bool contains(int k) const
{
unsigned p = pos[k];
return (p < n
&& key[p] == k);
}
void insert(int k)
{
if (contains(k))
return;
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void extend(int k)
{
assert(!contains(k));
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void erase(int k)
{
if (!contains(k))
return;
unsigned p = pos[k];
--n;
if (p != n)
{
int ell = key[n];
pos[ell] = p;
key[p] = ell;
}
}
int ith(int i)
{
assert(i >= 0 && i < (int)n);
return key[i];
}
};
using UllmanSet = BasedUllmanSet<0>;
using UllmanSet1 = BasedUllmanSet<1>;
The priority queue is implemented as followed. I like to print out the values inside the queue using std::cout.
PriorityQ<std::pair<int, int>, Comp> frontierq;
class Comp
{
public:
Comp() {}
bool operator()(const std::pair<int, int> &lhs,
const std::pair<int, int> &rhs) const
{
return (lhs.second > rhs.second
|| (lhs.second == rhs.second
&& lhs.first > rhs.first));
}
};
class PriorityQ
{
public:
Comp comp;
std::vector<T> v;
unsigned n;
public:
PriorityQ() : n(0) {}
PriorityQ(Comp comp_) : comp(comp_), n(0) {}
size_t size() const { return n; }
void clear() { n = 0; }
bool empty() { return n == 0; }
void push(const T &x)
{
assert(v.size() >= n);
if (v.size() == n)
v.push_back(x);
else
v[n] = x;
++n;
std::push_heap(&v[0], &v[n], comp);
}
const T &pop()
{
assert(n > 0);
std::pop_heap(&v[0], &v[n], comp);
--n;
return v[n];
}
const T &top()
{
assert(n > 0);
return v[0];
}
};
C++ standard containers do get this esoteric. If you have another question about the priority queue you should make another post.
I am implementing a container class that ensures uniqueness among the elements and restricts insertion and deletion to only the end only. Somewhat like a stack of unique elements or an ordered set with functions like push and pop. And it must also have a fixed maximum size.
template <class T, int max_size>
class FixedSizedUniqueStack
{
std::vector<T> m_vec;
std::unordered_set<T> m_uset;
public:
FixedSizedUniqueStack():m_vec(max_size),m_uset(){}
bool push(T x)
{
bool success = true;
if( m_uset.insert(x).second ) m_vec.push_back(x);
else success = false;
return success;
}
void pop()
{
if(m_vec.size() > 0)
{
m_uset.erase(m_vec.back());
m_vec.pop_back();
}
}
T back()
{
return m_vec.back();
}
};
#include <vector>
#include <unordered_set>
#include <initializer_list>
template <class T, int max_size>
class FixedSizedUniqueStack: public std::initializer_list<T>
{
protected:
std::vector<T> m_vec;
std::unordered_set<T> m_uset;
public:
FixedSizedUniqueStack():m_vec(),m_uset(){}
FixedSizedUniqueStack( const FixedSizedUniqueStack &x)
{
m_vec = x.m_vec;
m_uset = x.m_uset;
}
FixedSizedUniqueStack& operator= ( const FixedSizedUniqueStack &x)
{
if (this != &x)
{
m_vec = x.m_vec;
m_uset = x.m_uset;
}
return *this;
}
auto size() const -> decltype(m_vec.size())
{
return m_vec.size();
}
int push(const std::initializer_list<T>& il)
{
int errors = 0;
for (auto x: il)
{
if( push(x) )
{
errors++;
}
}
return errors;
}
int push(const T& x)
{
int error =0;
if(m_vec.size() < max_size)
{
if( x < start)
{
error = 1;
}
else if( x > stop)
{
error = 2;
}
else
{
if( m_uset.insert(x).second ) m_vec.push_back(x);
else error = 3;
}
}
else
{
error = 4;
}
return error;
}
void pop()
{
if(!m_vec.empty())
{
m_uset.erase(m_vec.back());
m_vec.pop_back();
}
}
T back()
{
return m_vec.back();
}
auto cbegin() const -> decltype(m_vec.cbegin())
{
return m_vec.cbegin();
}
auto cend() const -> decltype(m_vec.cend())
{
return m_vec.cend();
}
auto begin() const -> decltype(m_vec.begin())
{
return m_vec.begin();
}
auto end() const -> decltype(m_vec.end())
{
return m_vec.end();
}
auto empty() ->decltype(m_vec.empty())
{
return m_vec.empty();
}
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();
}