Search code examples
c++classrecursionsingly-linked-listfunction-definition

How to handle recursion in member functions?


E.g., I have an empty function to clear a linked list:

void empty(Node* head) {
        if (head->next) { empty(head->next); }
        delete head;
        head = nullptr;
    }

But then I created a class for the linked list, so now I don't need to pass the head argument:

void empty() {
        if (head->next) { empty(head->next); }
        delete head;
        head = nullptr;
    }

But empty(head->next) line is obviously wrong as empty doesn't take any arguments. The idea comes to my mind to create a function inside a function (with lambda), something like this:

void empty() {
        std::function<void(Node*)> emptyWrapper = [&] (Node* l_head) {
            if (l_head->next) { emptyWrapper(l_head->next); }
            delete l_head;
            l_head = nullptr;
        };
        emptyWrapper(head);
    }

But I'm wondering if there's any better way to do it. Lambdas became kind of idee fixe for me recently.


Solution

  • A general approach is to declare a public member function that in turn calls a private static recursive member function.

    Pay attention that the name empty sounds confusing. It is better to name the function for example like clear.

    Here you are

    #include <functional>
    
    //...
    
    class List
    {
    public:
        //...
        void clear() 
        {
            clear( head );
        }
    
    private:
        static void clear( Node * &head )
        {
            if ( head )
            {
                delete std::exchange( head, head->next );
                clear( head ); 
            }
        }
        //...
    }
    

    The same approach can be used without defining an auxiliary static function.

    void clear()
    {
        if ( head )
        {
            delete std::exchange( head, head->next );
            clear();
        }
    }
    

    Here is a demonstrative program.

    #include <iostream>
    #include <iomanip>
    #include <functional>
    
    template <typename T>
    class List
    {
    private:
        struct Node
        {
            T data;
            Node *next;
        } *head = nullptr;
    
    public:
        void push_front( const T &data )
        {
            head = new Node { data, head };
        }
    
        friend std::ostream & operator <<( std::ostream &os, const List &list )
        {
            for ( Node *current = list.head; current; current = current->next )
            {
                os << current->data << " -> ";
            }
    
            return os << "null";
        }
    
        bool empty() const { return head== nullptr; }
    
        void clear()
        {
            if ( head )
            {
                delete std::exchange( head, head->next );
                clear();
            }
        }
    };
    
    int main() 
    {
        List<int> list;
    
        const int N = 10;
    
        for ( int i = N; i != 0; )
        {
            list.push_front( i-- );
        }
    
        std::cout << list << '\n';
    
        list.clear();
    
        std::cout << "list is empty " << std::boolalpha << list.empty() << '\n';
    
        return 0;
    }
    

    The program output is

    1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> null
    list is empty true