Custom iterator for a linked list class
Your iterator is missing a few important details:

You should provide the pre- and post-increment operators (++it and it++). Currently, you only have the pre-increment version.

It might also be good to provide the -&gt; operator, since some people prefer the it-&gt;something syntax over the (*it).something one.

The comparison and dereference operators should be const. Remember Const Correctness.

The copy constructor is just performing a memberwise copy of the underlying data, so you don't need to provide one and can let the compiler default it.

The Standard Library containers always provide two flavors of iterators, the iterator type, pointing to mutable data, and the const_iterator type, pointing to immutable data. It is easy to adapt your class to support both by providing a conversion operator and inheriting from std::iterator (see the following example).

Decide which course of action should be taken when incrementing and dereferencing an invalid iterator. E.g.: list.end()++;. Should it trigger an assertion? Throw an exception? Do nothing as it is now? I would at least assert to help the debugging process. You might find exceptions more appropriate in your context.


The above points applied to your code:
#include &lt;cassert&gt;      // assert
#include &lt;cstddef&gt;      // ptrdiff_t
#include &lt;iterator&gt;     // iterator
#include &lt;type_traits&gt;  // remove_cv
#include &lt;utility&gt;      // swap

template
&lt;
    class Type,
    class UnqualifiedType = std::remove_cv_t&lt;Type&gt;
&gt;
class ForwardIterator 
    : public std::iterator&lt;std::forward_iterator_tag,
                           UnqualifiedType,
                           std::ptrdiff_t,
                           Type*,
                           Type&amp;&gt;
{
    node&lt;UnqualifiedType&gt;* itr;

    explicit ForwardIterator(node&lt;UnqualifiedType&gt;* nd) 
        : itr(nd) 
    { 
    }

public:

    ForwardIterator()   // Default construct gives end.
        : itr(nullptr) 
    { 
    }

    void swap(ForwardIterator&amp; other) noexcept
    {
        using std::swap;
        swap(itr, other.iter);
    }

    ForwardIterator&amp; operator++ () // Pre-increment
    {
        assert(itr != nullptr &amp;&amp; &quot;Out-of-bounds iterator increment!&quot;);
        itr = itr-&gt;next;
        return *this;
    }

    ForwardIterator operator++ (int) // Post-increment
    {
        assert(itr != nullptr &amp;&amp; &quot;Out-of-bounds iterator increment!&quot;);
        ForwardIterator tmp(*this);
        itr = itr-&gt;next;
        return tmp; 
    }

    // two-way comparison: v.begin() == v.cbegin() and vice versa
    template&lt;class OtherType&gt;
    bool operator == (const ForwardIterator&lt;OtherType&gt;&amp; rhs) const
    {
        return itr == rhs.itr;
    }
    
    template&lt;class OtherType&gt;
    bool operator != (const ForwardIterator&lt;OtherType&gt;&amp; rhs) const
    {
        return itr != rhs.itr;
    }

    Type&amp; operator* () const
    {
        assert(itr != nullptr &amp;&amp; &quot;Invalid iterator dereference!&quot;);
        return itr-&gt;data;
    }

    Type&amp; operator-&gt; () const
    {
        assert(itr != nullptr &amp;&amp; &quot;Invalid iterator dereference!&quot;);
        return itr-&gt;data;
    }

    // One way conversion: iterator -&gt; const_iterator
    operator ForwardIterator&lt;const Type&gt;() const
    {
        return ForwardIterator&lt;const Type&gt;(itr);
    }
};

// `iterator` and `const_iterator` used by your class:
typedef ForwardIterator&lt;T&gt; iterator;
typedef ForwardIterator&lt;const T&gt; const_iterator;

Note: In the example, I've assumed that the end of your list or an invalid iterator are marked by a null pointer. You'll need to change that if you are using some other method, such as a dummy sentry node.