I've implemented a random_access_iterator for a custom library (which is templated to be reused both as const iterator and non-const iterator), but it's causing memory leaks while doing something like std::sort(container.begin(), container.end() (container.begin()/end() return iterator instance.
What's wrong with my implementation?
template <bool is_const_iterator = false>
class meta_iterator : public std::iterator<std::random_access_iterator_tag, T> {
public:
typedef T value_type;
typedef std::ptrdiff_t difference_type;
typedef typename std::conditional<is_const_iterator, const value_type &,
value_type &> reference;
typedef std::random_access_iterator_tag iterator_category;
typedef typename std::conditional<is_const_iterator, value_type const *,
value_type *>::type pointer;
typedef meta_iterator self_type;
meta_iterator(T *ptr) : ptr_(ptr) {}
meta_iterator(const meta_iterator<true> &other) : ptr_(other.ptr_) {}
self_type operator+(difference_type value) {
ptr_ += value;
return *(this);
};
self_type operator-(difference_type value) {
ptr_ -= value;
return *(this);
};
difference_type operator-(const self_type &other) {
return ptr_ - other.ptr_;
}
T &operator[](difference_type value) const { return *ptr_[value]; }
bool operator==(const self_type &other) const { return ptr_ == other.ptr_; }
bool operator!=(const self_type &other) const { return !(*this == other); }
bool operator>=(const self_type &other) const { return !((*this) < other); }
bool operator<=(const self_type &other) const { return !((*this) > other); }
bool operator<(const self_type &other) const { return ptr_ < other.ptr_; }
bool operator>(const self_type &other) const { return ptr_ < other.ptr_; }
self_type &operator=(const self_type &other) {
ptr_ = other.ptr_;
return *(this);
}
T *operator->() const { return ptr_; }
T &operator*() const { return *ptr_; }
self_type &operator--() {
ptr_--;
return *this;
}
self_type operator--(int) {
self_type temp(*this);
--(*this);
return (temp);
}
self_type &operator++() {
ptr_++;
return *this;
}
self_type operator++(int) {
self_type temp(*this);
--(*this);
return (temp);
}
self_type &operator+=(difference_type value) {
ptr_ += value;
return *(this);
}
self_type &operator-=(difference_type value) {
ptr_ -= value;
return *(this);
}
friend class meta_iterator<true>;
friend class meta_iterator<false>;
private:
T *ptr_;
};
Don't know if it causes a memory leak, but these two operators
self_type operator+(difference_type value) {
ptr_ += value;
return *(this);
};
self_type operator-(difference_type value) {
ptr_ -= value;
return *(this);
};
should just return a new iterator, and not update the stored ptr_.
Also, there is a typo in
self_type operator++(int) {
self_type temp(*this);
--(*this);
return (temp);
}
making it go in the wrong direction. That will probably confuse some loops.
Related
I’m trying to implement my stl-like container, which in fact will be an incomplete version of a map.
Faced a problem at the time of implementation of the erase method, I do not understand how to delete a pair of <key, value>.
I am stuck, so I ask for help. Can someone please guide me to the solution? Here is the code.
P.S.: Im only starting to learn C++;
void erace(const key_type& Key)
{
int n = 1;
for (iterator i = begin(); i != end(); ++i, n++)
{
if (i->first == Key)
{
//TO DO.
}
}
}
Whole code:
template < typename Key, typename T, typename Compare = std::less<Key>, typename Allocator = std::allocator< std::pair<const Key, T> > >
class map
{
public:
class miterator
{
public:
typedef miterator self_type;
typedef std::pair<const Key, T> value_type;
typedef std::pair<const Key, T>& reference;
typedef std::pair<const Key, T>* pointer;
typedef std::bidirectional_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
miterator(pointer ptr) : ptr_(ptr) { };
miterator() {}
self_type operator=(const self_type& other) { ptr_ = other.ptr_; return *this; }
self_type operator++() { self_type i = *this; ptr_++; return i; }
self_type operator--() { self_type i = *this; ptr_--; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
self_type operator--(int junk) { ptr_--; return *this; }
reference operator*() { return *ptr_; }
pointer operator->() { return ptr_; }
pointer operator&() { return ptr_; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
class mconst_iterator
{
public:
typedef mconst_iterator self_type;
typedef std::pair<const Key, T> value_type;
typedef std::pair<const Key, T>& reference;
typedef std::pair<const Key, T>* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
mconst_iterator(pointer ptr) : ptr_(ptr) { };
mconst_iterator() {}
self_type operator=(const self_type& other) { ptr_ = other.ptr_; return *this; }
self_type operator++() { self_type i = *this; ptr_++; return i; }
self_type operator--() { self_type i = *this; ptr_--; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
self_type operator--(int junk) { ptr_--; return *this; }
reference operator*() { return *ptr_; }
pointer operator->() { return ptr_; }
pointer operator&() { return ptr_; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
pointer ptr_;
};
typedef map<Key, T, Compare, Allocator> mymap;
typedef Key key_type;
typedef T mapped_type;
typedef std::pair<const Key, T> value_type;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef Compare key_compare;
typedef Allocator allocator_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef miterator iterator;
typedef mconst_iterator const_iterator;
typedef std::reverse_iterator<miterator> reverse_iterator;
typedef std::reverse_iterator<mconst_iterator> const_reverse_iterator;
map()
: size(0), capacity(20), data(Allocator().allocate(20))
{
}
map(const mymap& _Rhs)
: size(_Rhs.size), capacity(_Rhs.size + 20), data(Allocator().allocate(_Rhs.size))
{
int count = 0;
for (iterator i = &_Rhs.data[0]; i != &_Rhs.data[_Rhs.size]; ++i, ++count)
{
Allocator().construct(&data[count], *i);
}
}
~map()
{
if (!empty())
{
Allocator().deallocate(data, capacity);
}
}
mymap& insert(const value_type& pair)
{
if (!is_present(pair))
{
if (++size >= capacity)
{
reserve(capacity * 2);
}
Allocator().construct(&data[size - 1], pair);
return *this;
}
}
bool is_present(const value_type& pair)
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == pair.first)
{
return true;
}
return false;
}
}
bool has_key(const key_type& _Key)
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == _Key)
{
return true;
}
}
return false;
}
mapped_type& operator[](const key_type& _Key)
{
if (has_key(_Key))
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == _Key)
{
return i->second;
}
}
}
size_type op = size;
insert(value_type(_Key, mapped_type()));
return data[op].second;
}
mymap& reserve(size_type _Capacity)
{
int count = 0;
if (_Capacity < capacity)
{
return *this;
}
pointer buf = Allocator().allocate(_Capacity);
for (iterator i = begin(); i != end(); ++i, ++count)
{
Allocator().construct(&buf[count], *i);
}
std::swap(data, buf);
Allocator().deallocate(buf, capacity);
capacity = _Capacity;
return *this;
}
void erace(const key_type& Key)
{
int n = 1;
for (iterator i = begin(); i != end(); ++i, n++)
{
if (i->first == Key)
{
//TO DO
}
}
}
size_type get_size() const { return get_size; }
bool empty() const
{
return size == 0;
}
iterator clear()
{
~map();
}
iterator begin()
{
return &data[0];
}
iterator end()
{
return &data[size];
}
reverse_iterator rbegin()
{
return &data[0];
}
reverse_iterator rend()
{
return &data[size];
}
const_iterator cbegin() const
{
return &data[0];
}
const_iterator cend() const
{
return &data[size];
}
const_reverse_iterator rbegin() const
{
return &data[0];
}
const_reverse_iterator rend() const
{
return &data[size];
}
iterator find(const key_type& Key)
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == Key)
{
return i;
}
}
iterator res = end();
return res;
}
private:
pointer data;
size_type size, capacity;
};
Since you represent the map as an array of pairs, this is the same as erasing an element from an array.
Since the order isn't important, you can swap the last element with the one you're removing, then destroy the removed element and adjust the size.
I tried to implement iterators for a class of mine and surprisingly I got the following:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second
candidate 1: 'Iterator Iterator::operator+(const ptrdiff_t&) [with T = int; ptrdiff_t = long long int]'
candidate 2: 'operator+(int, unsigned int)'
Here's the Iterator code:
template<typename T>
class Iterator {
public:
Iterator(T *p = nullptr) { this->ptr = p; }
Iterator(const Iterator<T>& iter) = default;
Iterator<T>& operator=(const Iterator<T>& iter) = default;
Iterator<T>& operator=(T* p) { this->ptr = p; return *this; }
operator bool() const { return this->ptr ? true : false; }
bool operator==(const Iterator<T>& p) const { return this->ptr == p.getConstPtr(); }
bool operator!=(const Iterator<T>& p) const { return this->ptr != p.getConstPtr(); }
Iterator<T>& operator+=(const ptrdiff_t& v) { this->ptr += v; return *this; }
Iterator<T>& operator-=(const ptrdiff_t& v) { this->ptr -= v; return *this; }
Iterator<T>& operator++() { ++this->ptr; return *this; }
Iterator<T>& operator--() { --this->ptr; return *this; }
Iterator<T> operator++(int) { auto temp(*this); ++this->ptr; return temp; }
Iterator<T> operator--(int) { auto temp(*this); --this->ptr; return temp; }
Iterator<T> operator+(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr += v; auto temp(*this); this->ptr = oldPtr; return temp; }
Iterator<T> operator-(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr -= v; auto temp(*this); this->ptr = oldPtr; return temp; }
ptrdiff_t operator-(const Iterator<T>& p) { return std::distance(p.getPtr(), this->getPtr()); }
T& operator*() { return *(this->ptr); }
const T& operator*() const { return *(this->ptr); }
T* operator->() { return this->ptr; }
T* getPtr() const { return this->ptr; }
const T* getConstPtr() const { return this->ptr; }
private:
T *ptr;
};
And here's how I typedef it inside my class:
template<typename T>
class ExampleClass {
public:
// ...
typedef Iterator<T> iterator;
typedef Iterator<const T> const_iterator;
// ...
iterator begin() { return iterator(&this->ptr()[0]); }
iterator end() { return iterator(&this->ptr()[this->size()]); }
const_iterator cbegin() { return const_iterator(&this->ptr()[0]); }
const_iterator cend() { return const_iterator(&this->ptr()[this->size()]); }
// ...
// A function where I use the operator+
void slice(unsigned int first, unsigned int last) {
// ...
auto it = this->begin() + first; // <--------
// ...
}
};
Maybe I am missing something but how (Iterator, ptrdiff_t) and (int, unsigned int) are ambiguous?
I haven't compiled this, but the problem appears to be that operator bool(); it provides an implicit conversion to bool, which is, in turn, convertible to int. Iterators in general don't provide their own validation, so this is unusual. If you need it, mark it explicit. That will prevent the implicit conversion.
I am stuck trying to understand where this error comes from:
error: ‘value_type’ in ‘struct std::iterator_traits<sha::Vector<int>::h_iterator>’ does not name a type
I am trying to create a std::vector wrapper and inherit iterator as well.
I don't get why the compilator cannot infer the 'value_type' or 'difference_type'.
Here is my class definition:
template <typename T>
class Vector
{
public:
explicit Vector(std::initializer_list<T> init) : data(init) {}
~Vector() {}
class h_iterator : std::iterator<std::random_access_iterator_tag, T>
{
public:
h_iterator(typename std::vector<T>::iterator it,
Vector<T>* owner) :
it(it), owner(owner) {}
T operator *() const { return *it; }
const h_iterator &operator ++() { ++it; return *this; }
h_iterator operator ++(int) { h_iterator copy(*this); ++it; return copy; }
const h_iterator &operator --() { --it; return *this; }
h_iterator operator --(int) { h_iterator copy(*this); --it; return copy; }
h_iterator& operator =(const h_iterator& other){ this->it =other.it; return *this;}
bool operator ==(const h_iterator &other) const { return it == other.it; }
bool operator !=(const h_iterator &other) const { return it != other.it; }
bool operator <(const h_iterator &other) const { return it < other.it; }
bool operator >(const h_iterator &other) const { return it > other.it; }
bool operator <=(const h_iterator &other) const { return it <= other.it; }
bool operator >=(const h_iterator &other) const { return it >= other.it; }
h_iterator operator +(const long int &delta) const
{
h_iterator copy(*this);
it += delta;
return copy;
}
h_iterator& operator +=(const long int& delta)
{
it = it + delta;
return *this;
}
h_iterator operator -(const long int &delta) const
{
h_iterator copy(*this);
it -= delta;
return copy;
}
h_iterator& operator -=(const long int& delta)
{
it = it - delta;
return *this;
}
T operator [](const long int &delta) const { return *(it + delta); }
private:
typename std::vector<T>::iterator it; // Iterator
Vector<T>* owner; // Cannot be null as long as the iterator is valid
};
// Preserve normal iterator accesses
typename std::vector<T>::iterator begin() { return data.begin(); }
typename std::vector<T>::iterator end() { return data.end(); }
const typename std::vector<T>::iterator cbegin() const { return data.cbegin(); }
const typename std::vector<T>::iterator cend() const { return data.cend(); }
// Observale iterator
h_iterator h_begin() { return h_iterator(data.begin(), this); }
h_iterator h_end() { return h_iterator(data.end(), this); }
// Implement Meta-Language functions
//...
private:
Vector() {}
Vector operator=(Vector&) {} // Not Implemented
std::vector<T> data; // Vector wrapper
};
Here is the code that makes the compilation failed:
typedef Vector<int> Container;
typedef Container::h_iterator IT;
typedef std::less<typename
std::iterator_traits<Vector<int>::h_iterator>::value_type> Compare;
Why does this compile error happen?
When you use:
class h_iterator : std::iterator<std::random_access_iterator_tag, T>
the base class is a private base class. The details of the base class are not accessible to clients of h_iterator. Make the derivation public.
class h_iterator : public std::iterator<std::random_access_iterator_tag, T>
Hi everyone,
I'm having problems implementing my own List with iterator for the project at Univeristy. What should I do for correct iterating over loop? Could somebody help me? Sory for my English if is incorrect.
#ifndef __List__
#define __List__
template <class type>
class List
{
public:
struct Node
{
type value;
Node* next;
};
Node* root;
class iterator
{
public:
typedef iterator self_type;
typedef Node& reference;
typedef Node* pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
iterator(pointer ptr) : ptr_(ptr) { }
self_type operator++() { self_type i = *this->ptr_->next; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
reference operator*() { return ptr_; }
type operator->() { return ptr->value; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
class const_iterator
{
public:
typedef const_iterator self_type;
typedef type value_type;
typedef Node& reference;
typedef Node* pointer;
typedef int difference_type;
typedef std::forward_iterator_tag iterator_category;
const_iterator(pointer ptr) : ptr_(ptr) { }
self_type operator++() { self_type i = *this->ptr_->next; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
const reference operator*() { return *ptr_; }
const type operator->() { return ptr->value; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
List();
List(std::initializer_list<type> vals);
~List();
iterator begin()
{
return iterator(root);
}
iterator end()
{
return iterator(nullptr);
}
const_iterator begin() const
{
return const_iterator(root);
}
const_iterator end() const
{
return const_iterator(nullptr);
}
Node* last();
void push_back(type obj);
};
template <class type>
List<type>::List()
{
root = nullptr;
}
template <class type>
List<type>::List(std::initializer_list<type> vals)
{
root = nullptr;
for (auto& elem : vals)
push_back(elem);
}
template <class type>
List<type>::~List()
{
}
template <class type>
typename List<type>::Node* List<type>::last()
{
Node* tmp = root;
while (tmp->next != nullptr)
tmp = tmp->next;
return tmp;
}
template <class type>
void List<type>::push_back(type obj)
{
Node* tmp = new Node;
tmp->value = obj;
tmp->next = nullptr;
if (root == nullptr)
root = tmp;
else
{
Node* l = last();
l->next = tmp;
}
}
#endif
I would like to iterate over my List like the first loop or even the second.
int main()
{
List<Product*> ProductBase{ new Product("Lubella Spaghetti 500 g", 10.0, 3.1, 0.23, 1), new Product("Nescafé Gold Blend 200 g", 20.0, 1.2, 0.23, 1) };
for (auto i = ProductBase.begin(); i != ProductBase.end(); ++i)
i->display_product();
for (auto elem : ProductBase)
elem->display_product();
system("PAUSE");
}
In the operator++ of the iterator and const_iterator you need to add
_ptr = ptr_->next
and I would rather not implement
self_type operator++(int junk)
in the iterator class. List iterators typically can only advance one step forward.
Also, in the const_iterator, make sure you only return const pointers, so that the compiler will issue an error if the caller tries to use the const_iterator to mutate the list.
Following on from this question: std::list implementation & pointer arithemetic.
I want to implement a list iterator that is interchangeable with other common containers types and their respective iterators, so I want to use operators such as: --, ++, * and be able to declare iterators as normal, so: list::iterator iter = list.begin();
The --, ++ operators now work as they should, but I ran up against the problem of de-referencing the iterator, as structs can't return a value: T iterator::operator*()
template <class T>
struct element {
element<T> *prev = NULL;
element<T> *next = NULL;
T data;
};
template <typename T>
class list {
public:
list::list();
element<T>* current;
struct iterator{
element<T>* iterator::operator++(){
this = *this->next; ..whatever it works
}
element<T>* iterator::operator--()
T iterator::operator*()
}
};
the iterators could look something like this:
(declared inside the list template)
struct iterator;
struct const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T>
{
const_iterator() = default;
T operator*() { return itm->data; }
const T* operator->() { return &(itm->data); }
const_iterator operator++() { itm = itm->next; return *this; }
const_iterator operator--() { itm = itm->prev; return *this; }
const_iterator operator++(int) { const_iterator ret=*this; itm = itm->next; return ret; }
const_iterator operator--(int) { const_iterator ret=*this; itm = itm->prev; return ret; }
bool operator==(const_iterator oth) const { return itm==oth.itm; }
bool operator!=(const_iterator oth) const { return itm!=oth.itm; }
private:
element<T>* itm = nullptr;
const_iterator(element<T>* i) : itm(i) {}
friend
class list;
friend
struct iterator;
};
struct iterator : public std::iterator<std::bidirectional_iterator_tag, T>
{
iterator() = default;
T& operator*() { return itm->data; }
T* operator->() { return &(itm->data); }
iterator operator++() { itm = itm->next; return *this; }
iterator operator--() { itm = itm->prev; return *this; }
iterator operator++(int) { iterator ret=*this; itm = itm->next; return ret; }
iterator operator--(int) { iterator ret=*this; itm = itm->prev; return ret; }
bool operator==(iterator oth) const { return itm==oth.itm; }
bool operator!=(iterator oth) const { return itm!=oth.itm; }
operator const_iterator() { return {itm}; }
private:
element<T>* itm = nullptr;
iterator(element<T>* i) : itm(i) {}
friend
class list;
};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
this needs
#include <iterator>
to compile