0

I have a simple class LinkedList with overloaded stream insertion and indexing operators.

LinkedList.h

#pragma once
#include <functional>
#include <vector>
#include <ostream>

namespace linkedlist
{
    class LinkedList
    {
        friend std::ostream& operator<<(std::ostream&, const LinkedList&);

        struct Node;
        Node *head;
        int n;

        struct Node
        {
            double data;
            Node *next;

            Node(double data) : data(data), next(nullptr) {} 
        };

    public:
        LinkedList() = default;
        ~LinkedList();

    public:
        LinkedList& add(double);
        const double& operator[](int index) const;
        double& operator[](int index);
    };
}


LinkedList.cpp

#include "LinkedList.h"

namespace linkedlist
{
    LinkedList::~LinkedList()
    {
        while (head)
        {
            Node *toDelete = head;
            head = head->next;
            delete toDelete;
        }

        head = nullptr;
    }

    LinkedList& LinkedList::add(double data)
    {
        Node *newNode = new Node(data);

        if (head == nullptr)
            head = newNode;

        else 
        {
            Node *temp = head; 

            while (temp->next)
            {
                temp = temp->next;
            }
            temp->next = newNode; 
        }

        n++;
        return *this;
    }

    const double& LinkedList::operator[](int index) const
    {
        Node *temp = head;

        while (--index)
            temp = temp->next;

        return temp->data;
    }

    double& LinkedList::operator[](int index)
    {
        Node *temp = head;

        while (index-- > 0)
            temp = temp->next;

        return temp->data;
    }


    std::ostream& operator<<(std::ostream& stream, const LinkedList& list)
    {
        for (LinkedList::Node *temp = list.head; temp != nullptr; temp = temp->next)
            stream << temp->data << " ";

        return stream;
    }

}

Both operator functions are tested and are working correctly.

However, when stepping into the last line of the main function

int main()
{
    LinkedList A;
    A.add(3).add(2).add(5).add(7);

//  cout << A << endl;     // works!
//  cout << A[0] << endl;  // works!
    cout << A[0] << " " << A[1] << " " << A[2] << " " << A[3] << " " << endl;   
}

I noticed a strange behavior of the stream insertion operator.

Since the associativity of the operator doesn't change even when it is overloaded, I expected the calls to operator[] to be executed from left to right and after each one an element to be printed and ostream reference returned (to allow proper chaining of the operator).

Instead, operators were called from the right-most one

first visit to the operator[]

And after the four consecutive calls to the operator[] the execution went to the ostream class and the elements were printed to the console.

Is this some sort of buffering? Why are chained << operators behaving like this?

0lt
  • 283
  • 2
  • 13
  • 2
    The order of evaluation is unspecified. See, for example, [this question](https://stackoverflow.com/questions/8931249/ostream-chaining-output-order). – G.M. Jan 31 '18 at 12:25
  • Associativity applies to operators, not their operands. – molbdnilo Jan 31 '18 at 12:35
  • @G.M. the order of evaluation for the `A[?]` is unspecified, but the `operator<<` will be called from left to right, no? – 463035818_is_not_an_ai Jan 31 '18 at 12:35
  • @tobi303 Yes, I was referring specifically to the order in which the various calls to `operator[]` were evaluated. Sorry, should've been more careful with my wording in the comment. – G.M. Jan 31 '18 at 12:41

0 Answers0