Skip to content

Instantly share code, notes, and snippets.

@jeetsukumaran
Created February 18, 2010 02:33
Show Gist options
  • Save jeetsukumaran/307264 to your computer and use it in GitHub Desktop.
Save jeetsukumaran/307264 to your computer and use it in GitHub Desktop.
Sample C++/STL custom iterator
// Sample custom iterator.
// By perfectly.insane (http://www.dreamincode.net/forums/index.php?showuser=76558)
// From: http://www.dreamincode.net/forums/index.php?showtopic=58468
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cassert>
template <typename T>
class fixed_array
{
public:
typedef int size_type;
class iterator
{
public:
typedef iterator self_type;
typedef T value_type;
typedef T& reference;
typedef T* 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_++; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
reference 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 const_iterator
{
public:
typedef const_iterator self_type;
typedef T value_type;
typedef T& reference;
typedef T* 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_++; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
const reference operator*() { return *ptr_; }
const 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_;
};
fixed_array(size_type size) : size_(size) {
data_ = new T[size_];
}
size_type size() const { return size_; }
T& operator[](size_type index)
{
assert(index < size_);
return data_[index];
}
const T& operator[](size_type index) const
{
assert(index < size_);
return data_[index];
}
iterator begin()
{
return iterator(data_);
}
iterator end()
{
return iterator(data_ + size_);
}
const_iterator begin() const
{
return const_iterator(data_);
}
const_iterator end() const
{
return const_iterator(data_ + size_);
}
private:
T* data_;
size_type size_;
};
int main()
{
fixed_array<double> point3d(3);
point3d[0] = 2.3;
point3d[1] = 3.2;
point3d[2] = 4.2;
for(fixed_array<double>::iterator i = point3d.begin(); i != point3d.end(); i++)
{
std::cout << *i << " ";
}
std::cout << std::endl;
std::vector<double> vec;
std::copy(point3d.begin(), point3d.end(), std::back_inserter(vec));
for(std::vector<double>::iterator i = vec.begin(); i != vec.end(); i++)
{
std::cout << *i << " ";
}
std::cout << std::endl;
return 0;
}
@apagel
Copy link

apagel commented Mar 13, 2014

This was a big help Thanks a bunch.

@DarkoVeberic
Copy link

you got the pre/post-fix wrong... it's the other way around.

@DarkoVeberic
Copy link

and

const pointer const_iterator::operator->()

should really be

const value_type* const_iterator::operator->()

since the first decl is equivalent to return type of value_type* const, which is not what you want...

@chnlkw
Copy link

chnlkw commented May 5, 2014

    const reference const_iterator::operator*() 

should be

    const value_type& const_iterator::operator*() 

@calmofthestorm
Copy link

Shouldn't the == and != operators be const? I get warnings with any_iterator if I leave them non-const.

@sikolyat
Copy link

posfix and prefix increment is implemented wrongly, they are reversed ;)

            self_type operator++() { self_type i = *this; ptr_++; return i; } // and this the prefix
            self_type operator++(int junk) { ptr_++; return *this; } // this should be the postfix 

see

http://www.learncpp.com/cpp-tutorial/97-overloading-the-increment-and-decrement-operators/

so correctly:

            self_type operator++() { ptr_++; return *this; } // PREFIX
            self_type operator++(int junk) { self_type i = *this; ptr_++; return i; } // POSTFIX

@thpica
Copy link

thpica commented Jul 21, 2015

You are missing a destructor for your class.
T* data_ is assigned with new, so no implicite destruction.
It leaks !

@DrLutzi
Copy link

DrLutzi commented Dec 24, 2015

An operator= is necessary, as well as an empty constructor since your iterator is of forward category:

iterator() {}
self_type operator=(const self_type& other) { ptr_ = other.ptr_; return *this; }

Other than that and everything above it helped me a lot, thanks!

source: http://www.cplusplus.com/reference/iterator/

@rodrigofns
Copy link

It leaks memory, a destructor is indispensable... and is pretty simple:
~fixed_array() { delete[] data_; }

@heeh
Copy link

heeh commented Jul 30, 2017

This is huge. Thank you for sharing.

@rmi111
Copy link

rmi111 commented Aug 11, 2017

The const_iterator does not accept iterator from non const FixedArray type.

`fixed_array point3d(3);
point3d[0] = 2.3;
point3d[1] = 3.2;
point3d[2] = 4.2;

for(fixed_array<double>::const_iterator i = point3d.begin(); i != point3d.end(); i++) //error
{
    std::cout << *i << " ";
}`

Is there any way you can make it accept it.

@seekingThat
Copy link

I wanted to use const_iterator and the following changes were required:
const_iterator cbegin() const
{
return const_iterator(data_);
}

    const_iterator cend() const
    {
        return const_iterator(data_ + size_);
    }

...
for(fixed_array::const_iterator i = point3d.cbegin(); i != point3d.cend(); i++)
{
std::cout << *i << " ";
}

is it possible to use the same functions begin() and end() ? how can we overload the same functionality for providing const_iterator ?

Thanks,

@nevzatseferoglu
Copy link

nevzatseferoglu commented Dec 18, 2019

You are missing a destructor for your class.
T* data_ is assigned with new, so no implicite destruction.
It leaks !

There would not be any leak , because these iterator classes are going to be an inner class of the specific container.
Specific container has its own destructor and it can handle it by its own.

@deiuch
Copy link

deiuch commented May 17, 2020

You are missing a destructor for your class.
T* data_ is assigned with new, so no implicite destruction.
It leaks !

There would not be any leak , because these iterator classes are going to be an inner class of the specific container.
Specific container has its own destructor and it can handle it by its own.

I think that this container will not have a way to do it since data_ is private. And you definitely should not allocate memory here if someone else is capable of deallocation. Just receive the pointer to memory in constructor then or take care of deallocation by yourself.

@deiuch
Copy link

deiuch commented May 17, 2020

And appropriate iterator_traits should be a good addition to this code :D

@nevzatseferoglu
Copy link

You are missing a destructor for your class.
T* data_ is assigned with new, so no implicite destruction.
It leaks !

There would not be any leak , because these iterator classes are going to be an inner class of the specific container.
Specific container has its own destructor and it can handle it by its own.

I think that this container will not have a way to do it since data_ is private. And you definitely should not allocate memory here if someone else is capable of deallocation. Just receive the pointer to memory in constructor then or take care of deallocation by yourself.

I mean that there is no leak from the point of iterator classes. Only allocation is happened by fixed_array class Therefore , you are right , there will be a leak , there is no destructor and also deallocation. Thanks for reminding.

@VirtualPirate
Copy link

Is there a way to reduce code. By some intelligent way. Because iterator and const_iterator are almost same except the const qualifications.

@LGoodacre
Copy link

LGoodacre commented Dec 6, 2020

@VirtualPirate

Is there a way to reduce code. By some intelligent way. Because iterator and const_iterator are almost same except the const qualifications.

You can have iterator inherit from const_iterator, and then run these overrides for iterator:

        value_type& operator*() { return const_cast<value_type&>(const_iterator::operator*()); }
        value_type* operator->() { return const_cast<value_type*>(const_iterator::operator->()); }    

The const_cast is what they use in STL, so I think it's safe :)

Looks like the typedefs have to stay, so it doesn't actually save that much code.

@amencke
Copy link

amencke commented Feb 7, 2021

excellent, thanks! nitpick: if you're implementing a container based on a fixed size C-style array, size_t would be a better choice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment