1

I have a my own container from GeeksforGeeks website I got from there code of container in below. I like to create an iterator class and capability of which will enable me to use for loop and function like begin and end in my container and for loop will be like something

MyClassForIterator iter;
for(iter=mycontainer_items_obj.begin();iter!=mycontainer_items_obj.end();iter++)
{
cout<<*iter<<endl
...
}

I like to know is this is possible in C++ and how to do it?

Vector template class

#include <bits/stdc++.h>
using namespace std;
template <typename T> class vectorClass
{

    // arr is the integer pointer
    // which stores the address of our vector
    T* arr;

    // capacity is the total storage
    // capacity of the vector
    int capacity;

    // current is the number of elements
    // currently present in the vector
    int current;

public:
    // Default constructor to initialise
    // an initial capacity of 1 element and
    // allocating storage using dynamic allocation
    vectorClass()
    {
        arr = new T[1];
        capacity = 1;
        current = 0;
    }

    // Function to add an element at the last
    void push(T data)
    {

        // if the number of elements is equal to the
        // capacity, that means we don't have space to
        // accommodate more elements. We need to double the
        // capacity
        if (current == capacity) {
            T* temp = new T[2 * capacity];

            // copying old array elements to new array
            for (int i = 0; i < capacity; i++) {
                temp[i] = arr[i];
            }

            // deleting previous array
            delete[] arr;
            capacity *= 2;
            arr = temp;
        }

        // Inserting data
        arr[current] = data;
        current++;
    }

    // function to add element at any index
    void push(int data, int index)
    {

        // if index is equal to capacity then this
        // function is same as push defined above
        if (index == capacity)
            push(data);
        else
            arr[index] = data;
    }

    // function to extract element at any index
    T get(int index)
    {

        // if index is within the range
        if (index < current)
            return arr[index];
    }

    // function to delete last element
    void pop() { current--; }

    // function to get size of the vector
    int size() { return current; }

    // function to get capacity of the vector
    int getcapacity() { return capacity; }

    // function to print array elements
    void print()
    {
        for (int i = 0; i < current; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    }
};

// Driver code
int main()
{
    vectorClass<int> v;
    vectorClass<char> v1;
    v.push(10);
    v.push(20);
    v.push(30);
    v.push(40);
    v.push(50);
    v1.push(71);
    v1.push(72);
    v1.push(73);
    v1.push(74);

    cout << "Vector size : " << v.size() << endl;
    cout << "Vector capacity : " << v.getcapacity() << endl;

    cout << "Vector elements : ";
    v.print();

    v.push(100, 1);

    cout << "\nAfter updating 1st index" << endl;

    cout << "Vector elements of type int : " << endl;
    v.print();
    // This was possible because we used templates
    cout << "Vector elements of type char : " << endl;
    v1.print();
    cout << "Element at 1st index of type int: " << v.get(1)
        << endl;
    cout << "Element at 1st index of type char: "
        << v1.get(1) << endl;

    v.pop();
    v1.pop();

    cout << "\nAfter deleting last element" << endl;

    cout << "Vector size of type int: " << v.size() << endl;
    cout << "Vector size of type char: " << v1.size()
        << endl;
    cout << "Vector capacity of type int : "
        << v.getcapacity() << endl;
    cout << "Vector capacity of type char : "
        << v1.getcapacity() << endl;

    cout << "Vector elements of type int: ";
    v.print();
    cout << "Vector elements of type char: ";
    v1.print();

    return 0;
}
user786
  • 3,902
  • 4
  • 40
  • 72
  • Of course it is possible in C++, but this is a fairly advanced, complicated topic that will require a lot of code written. Unfortunately, you are unlikely to learn these advanced, complicated C++ topics from some web site or a Youtube video. The only realistic way to learn advanced C++ topics is [with an advanced C++ textbook](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Sam Varshavchik Jul 01 '21 at 14:55
  • 2
    the container is broken because it is not following the [rule of 3/5](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). Unfortunately it isnt rare to find rather poor code on the site where you found this. The header should rather be "How to implement our own completely broken Vector Class in C++?" and instead of putting a disclaimer in the end saying "Attention reader! Don’t stop learning now." the disclaimer should be at the start saying "Attention reader! What follows is how to not implement a container". I don't like to rant, but I don't want you to get fooled – 463035818_is_not_an_ai Jul 01 '21 at 15:01

2 Answers2

1

Yes, totally possible in C++ just define a nested iterator class in your vector. Here I define a forward iterator, for your case you might want to pick a different category:

template <typename T> class vectorClass
{
    T* arr;
    int capacity;
    int current;

public:
    struct iterator 
    { 
        // You need these tags to provide introspection and conform
        // to standard implementations of iterators. If you were 
        // using Boost to define your iterator, you'd define those in
        // the base class.
        using iterator_category = std::forward_iterator_tag;
        using difference_type   = std::ptrdiff_t;
        using value_type        = T;
        using pointer           = value_type*;
        using reference         = value_type&;

        iterator(pointer ptr) : m_ptr(ptr) {}

        reference operator*() const { return *m_ptr; }
        pointer operator->() { return m_ptr; }

        // Prefix increment
        iterator& operator++() { m_ptr++; return *this; }  

        // Postfix increment
        iterator operator++(int) 
        { Iterator tmp = *this; ++(*this); return tmp; }

        friend bool operator== (const Iterator& a, const Iterator& b) 
        { return a.m_ptr == b.m_ptr; };
        friend bool operator!= (const Iterator& a, const Iterator& b) 
        { return a.m_ptr != b.m_ptr; };

    private:
        pointer m_ptr;
    };

    // Add begin/end functions to your class
    iterator begin() { return iterator(arr); }
    iterator end()   { return iterator(arr + curr); }

    /* 
    REST of the class remains the same 
    */
};

as you may have noticed in the comments, I mention the boost iterator facade library as a tool to define iterators. If that's an option for you, you can use it to eliminate much of the boilerplate.

Lorah Attkins
  • 5,331
  • 3
  • 29
  • 63
1

If your container stores its data internally as a contiguios array (as yours does) then you can simply use a pointer as your iterator:

template <typename T> class vectorClass
{
public:
    T* begin() { return arr; }
    T* end() { return arr + current; }

    T const* begin() const { return arr; }
    T const* end() const { return arr + current; }

    // ... etc...
};

This works because a pointer fulfils all the requirements of an iterator. In fact iterators are a generalization of pointers.

Galik
  • 47,303
  • 4
  • 80
  • 117