Subj : Re: chaining cout with a changing object To : borland.public.cpp.borlandcpp From : "Taras Kentrschynskyj" Date : Thu Sep 11 2003 10:55 am Thanks a lot, that cleared things up! I tested the following (on g++) to nicely illustrate your point: cout << (cout << 1, 1) << (cout << 2, 2) << (cout << 3, 3); which prints: 321123 "Benjamin Pratt" wrote: >Well, the problem here is that only the order in which the << operators are >executed is defined (left-to-right). But the order in which the arguments >are evaluated is not defined. In this case they are being evaluated from >right-to-left. This is also the behavior for VC6 (which I also tried it on). >You student has discovered the perils of undefined behavior. > >Let me see if I can explain it a little clearer. > >The standard does not define the order in which the _arguments_ are >evaluated. Thus the compilier chooses to evaluate each of the arguments (the >mystack.pop() statements) from right-to-left. The return values are stored >(probably in a stack :) ). So the return values from right-to-left were 321. > >Now the << stream operators are evaluated. This is guarenteed to be >evaluated from left-to-right. The leftmost 'mystack.pop()' statement was the >last to be evaluated; its result was 1. > >So 1 is sent to cout. Then 2, the middle argument. Finally the first >argument evaluated, 3, is sent to cout. > >You may be wondering why would a compiler vendor choose to evaluate >arguments right-to-left when the << operator will be evaluated >left-to-right. Because they can! :) Seriously, it is more effienct. Each of >the arguments can be stored from right-to-left in a stack, resulting in the >leftmost argument being on the top of the stack. Then when the << operators >are evaluated, each argument is pulled off the stack and feed to the stream. >Very simple and quick. Other methods would require FIFO techniques which are >a bit slower. > >The bottom line however, is that the code you posted results in undefined >behavior. On some compiliers it may work, on others not. Always best to >steer clear of this. Never rely on order of _argument_ evaluation. A related >example of undefined behavior is: > >int x = 5; >myfunc(--x, ++x); > >What is passed to myfunc? > >4,5 ? >or >5,6 ? > >Doesn't matter; don't do it, don't rely on order of argument evaluation. > > > > >"Taras Kentrschynskyj" wrote in message >news:3f5fa1b0$1@newsgroups.borland.com... >> >> One of my students at the Royal Institute of Technology in >> Stockholm, Sweden, draw my attention to the following: >> He had written an integer stack class (linked list >> implementation) with a pop operation returning the top item >> (data in the first node of the list, deleting this node after >> setting the top pointer to it's next), and tried the following: >> >> cout << mystack.pop() << mystack.pop() << mystack.pop(); >> >> If he had pushed 1, 2 and 3 on the stack, in that order, the >> output was, unexpectedly: >> 123 >> looks like a recursive call.. whereas the following: >> >> cout << mystack.pop(); >> cout << mystack.pop(); >> cout << mystack.pop(); >> >> of course gave the expected output: >> 321 >> >> I tried to track the first alternative, and found out that >> all three function calls are accomplished before any output >> in the chained statement. >> The same is true if you use another member function that doesn't >> change the object, e g get(int i), returning item no i in the >> stack. In this case, however, if you chain cout: >> >> cout << mystack.geti(1) << mystack.geti(2) << mystack.geti(3); >> >> the output comes in the chain order, not the reverse order as >> with the pop function. >> >> So, what is going on? How are the three return values saved >> in the chained statement? How does the pointer settings affect >> the order of the chained output? >> > > .