Search code examples
c++pointerstemplatesiteratorauto

Creating an custom iterator for a class that iterates through an array of pointers


The compilator says:

No callable 'begin' function found for type Array< int> *

No callable 'end' function found for type Array< int> *

it undeclared identifier

In the print function, I try to iterate through my array of pointers using for(auto it: this).

I followed this tutorial to create a custom iterator, and I don't know what I did wrong.

I'm not very sure if my iterator structure is defined correctly, because in his example he's using a simple array of integers, and I have an array of pointers to a T type.

My question is, what exactly should I edit to make the iterator working fine? I think I should edit some types from struct Iterator, but I'm not very sure what to edit. I use the auto keyword on the bottom, on the print function.

Full source code for my class is:

Array.h

#pragma once
#include<iostream>
using namespace std;
template<class T>
class Array
{
private:

    T** List; // lista cu pointeri la obiecte de tipul T*

    int Capacity; // dimensiunea listei de pointeri

    int Size; // cate elemente sunt in lista

public:
    
    struct Iterator {

        using iterator_category = std::forward_iterator_tag;
        using difference_type = std::ptrdiff_t;
        using value_type = T;
        using pointer = T *;  // or also value_type*
        using reference = T &;  // or also 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;
    };

    Iterator begin() { return Iterator(&List[0]); }
    Iterator end() { return Iterator(&List[Size-1]); }

    Array(); // Lista nu e alocata, Capacity si Size = 0

    ~Array(); // destructor

    Array(int capacity); // Lista e alocata cu 'capacity' elemente

    Array(const Array<T> &otherArray); // constructor de copiere

    T& operator[] (int index); // arunca exceptie daca index este out of range

    const Array<T>& operator+=(T *newElem); // adauga un element de tipul T la sfarsitul listei si returneaza this

    const Array<T>& Insert(int index, const T &newElem); // adauga un element pe pozitia index, retureaza this. Daca index e invalid arunca o exceptie

    const Array<T>& Delete(int index); // sterge un element de pe pozitia index, returneaza this. Daca index e invalid arunca o exceptie

    bool operator=(const Array<T> &otherArray);

    int GetSize();

    int GetCapacity();

    void realocateMemory();

    void printArray();

    bool isIndexValid(int);

};

template<class T>
bool Array<T>::isIndexValid(int index)
{
    //if (index < 0 || index > Size)
    //  throw Exceptions::InvalidIndex;
    return true;
}

template<class T>
void Array<T>::realocateMemory()
{
    T* helper = new T[Size];
    for (int i = 0;i < Size;i++)
        helper[i] = *List[i];

    delete[] List;
    Capacity *= 2;
    List = new T*[Capacity];
    for (int i = 0;i < Size;i++)
        List[i] = new T(helper[i]);
    delete[] helper;
}

template<class T>
int Array<T>::GetSize()
{
    return Size;
}

template<class T>
int Array<T>::GetCapacity()
{
    return Capacity;
}

template<class T>
Array<T>::Array() {
    Capacity = 1;
    Size = 0;
    List = new T*[Capacity];
}

template<class T>
Array<T>::Array(int cap) {
    Capacity = cap;
    List = new T*[Capacity];
}

template<class T>
Array<T>::~Array() {
    Capacity = 0;
    Size = 0;
    delete []List;
}

template<class T>
Array<T>::Array(const Array<T> &otherArray)
{
    delete[]List;
    Size = otherArray.GetSize();
    Capacity = otherArray.GetCapacity();
    List = new T*[Capacity];
    int poz = 0;
    for (auto it : otherArray)
        List[poz++] = it;

}

template<class T>
T& Array<T>::operator[] (int index)
{
    if (!isIndexValid(index))
        throw Exceptions::InvalidIndex;
    return List[index];
}


template<class T>
const Array<T>& Array<T>::operator+=(T *newElem) {
    if (Size == Capacity)
        realocateMemory();
    List[Size++] = newElem;
    return *this;
}


template<class T>
bool Array<T>::operator=(const Array<T> &otherArray)
{
    delete[] List;
    Capacity = otherArray.GetCapacity();
    Size = otherArray.GetSize();
    List = new T*[Capacity];

    for (int i = 0;i < Size;i++)
        List[i] = otherArray[i];    
    return true;
}


template<class T>
const Array<T>& Array<T>::Insert(int index, const T &newElem)
{

    if (Size == Capacity)
        realocateMemory();

    //shift one position to right
    for (int i = Size;i > index;i--)
        List[i] = List[i - 1];

    List[index] = new T(newElem);
    Size++;
    return *this;
}

template<class T>
const Array<T>& Array<T>::Delete(int index)
{
    for (int i = index;i < Size - 1;i++)
        List[i] = List[i + 1];
    Size--;
}


template<class T>
void Array<T>::printArray()
{
    for (int i = 0;i < Size;i++)
        std::cout << *List[i] << ' ';

    cout << "\n---------------------------------------\n";
    for (auto it : this)
        std::cout << *it << ' ';

    cout << "\n---------------------------------------\n";
}

main.cpp

#include "Array.h"
using namespace std;
#include <vector>
int main()
{

    Array<int>test;

    for (int i = 0;i < 100;i++)
        test += new int(i);
    int x = 444;
    test.Insert(0, x); //add x at index 0

    test.printArray();
    
    
    return 0;
}

Solution

  • Solved by changing some types from the structure.

    Because It is an array of pointers, it needs to have:

    • value_type should be a T* because every element from the array is a pointer

    • pointer should be a T** because it points to an array of pointers

    • and reference should be a T*& because is a reference through a pointer element from the array.

    Also, with some help from MatG, the for(auto it: this) should be changed to for(auto it: *this), because we need to use the dereferenced value of this class.

    Please correct me if I'm wrong.

    #pragma once
    #include<iostream>
    using namespace std;
    template<class T>
    class Array
    {
    private:
    
        T** List; // lista cu pointeri la obiecte de tipul T*
    
        int Capacity; // dimensiunea listei de pointeri
    
        int Size; // cate elemente sunt in lista
    
    public:
        
    
        struct Iterator {
    
            using iterator_category = std::forward_iterator_tag;
            using difference_type = std::ptrdiff_t;
            using value_type = T*;
            using pointer = T **;  // or also value_type*
            using reference = T *&;  // or also 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;
        };
    
        Iterator begin() { return Iterator(&List[0]); }
        Iterator end() { return Iterator(&List[Size]); }
    
        Array(); // Lista nu e alocata, Capacity si Size = 0
    
        ~Array(); // destructor
    
        Array(int capacity); // Lista e alocata cu 'capacity' elemente
    
        Array(const Array<T> &otherArray); // constructor de copiere
    
        T& operator[] (int index); // arunca exceptie daca index este out of range
    
        const Array<T>& operator+=(T *newElem); // adauga un element de tipul T la sfarsitul listei si returneaza this
    
        const Array<T>& Insert(int index, const T &newElem); // adauga un element pe pozitia index, retureaza this. Daca index e invalid arunca o exceptie
    
        const Array<T>& Delete(int index); // sterge un element de pe pozitia index, returneaza this. Daca index e invalid arunca o exceptie
    
        bool operator=(const Array<T> &otherArray);
    
        int GetSize();
    
        int GetCapacity();
    
        void realocateMemory();
    
        void printArray();
    
        bool isIndexValid(int);
    };
    
    template<class T>
    bool Array<T>::isIndexValid(int index)
    {
        //if (index < 0 || index > Size)
        //  throw Exceptions::InvalidIndex;
        return true;
    }
    
    template<class T>
    void Array<T>::realocateMemory()
    {
        T* helper = new T[Size];
        for (int i = 0;i < Size;i++)
            helper[i] = *List[i];
    
        delete[] List;
        Capacity *= 2;
        List = new T*[Capacity];
        for (int i = 0;i < Size;i++)
            List[i] = new T(helper[i]);
        delete[] helper;
    }
    
    template<class T>
    int Array<T>::GetSize()
    {
        return Size;
    }
    
    template<class T>
    int Array<T>::GetCapacity()
    {
        return Capacity;
    }
    
    template<class T>
    Array<T>::Array() {
        Capacity = 1;
        Size = 0;
        List = new T*[Capacity];
    }
    
    template<class T>
    Array<T>::Array(int cap) {
        Capacity = cap;
        List = new T*[Capacity];
    }
    
    template<class T>
    Array<T>::~Array() {
        Capacity = 0;
        Size = 0;
        delete []List;
    }
    
    template<class T>
    Array<T>::Array(const Array<T> &otherArray)
    {
        delete[]List;
        Size = otherArray.GetSize();
        Capacity = otherArray.GetCapacity();
        List = new T*[Capacity];
        int poz = 0;
        for (auto it : otherArray)
            List[poz++] = it;
    
    }
    
    template<class T>
    T& Array<T>::operator[] (int index)
    {
        if (!isIndexValid(index))
            throw Exceptions::InvalidIndex;
        return List[index];
    }
    
    
    template<class T>
    const Array<T>& Array<T>::operator+=(T *newElem) {
        if (Size == Capacity)
            realocateMemory();
        List[Size++] = newElem;
        return *this;
    }
    
    
    template<class T>
    bool Array<T>::operator=(const Array<T> &otherArray)
    {
        delete[] List;
        Capacity = otherArray.GetCapacity();
        Size = otherArray.GetSize();
        List = new T*[Capacity];
    
        for (int i = 0;i < Size;i++)
            List[i] = otherArray[i];    
        return true;
    }
    
    
    template<class T>
    const Array<T>& Array<T>::Insert(int index, const T &newElem)
    {
    
        if (Size == Capacity)
            realocateMemory();
    
        //shift one position to right
        for (int i = Size;i > index;i--)
            List[i] = List[i - 1];
    
        List[index] = new T(newElem);
        Size++;
        return *this;
    }
    
    template<class T>
    const Array<T>& Array<T>::Delete(int index)
    {
        for (int i = index;i < Size - 1;i++)
            List[i] = List[i + 1];
        Size--;
    }
    
    
    template<class T>
    void Array<T>::printArray()
    {
        for (int i = 0;i < Size;i++)
            std::cout << *List[i] << ' ';
    
        cout << "\n---------------------------------------\n";
        for (auto it : *this)
            std::cout <<*it << ' ';
    
        cout << "\n---------------------------------------\n";
    }