|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
I think that precedence and associativity only dictate how the infix expressions will be expanded into functional notation. That is a op1 b op2 c op3 d may be interpreted as op2(op1(a,b),op3(c,d)) according to the precedence and associativity rules, but this does not mean that op1 is evaluated first and op3 second. The only certain thing is that op2 will be evaluated last in this case. |
|
|
int i = 1; cout << i << ++i; may print 12 or 22 depending on the order of evaluation, which is unspecified. |
|
|
cout.operator<<(i)
returns an ostream reference, which is then used to call operator<<(++i)
. Therefore, the original value of "i" should always be output first before the second function call has its arguments evaluated; it is dependent on the return value of the first as an argument. It is still probably a bad idea to depend on that though; while they are separate function calls, they are still part of the same "expression" and the compiler may resolve/evaluate the function arguments independent of precedence and associativity rules.The version of the g++ g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 I often use this kind of expressions:
And I though I could just replace the pointer by an iterator and the result wold be the same. Now I see I was wrong. |
I think that precedence and associativity only dictate how the infix expressions will be expanded into functional notation. That is a op1 b op2 c op3 d may be interpreted as op2(op1(a,b),op3(c,d)) according to the precedence and associativity rules, but this does not mean that op1 is evaluated first and op3 second. The only certain thing is that op2 will be evaluated last in this case. |
a++ = b;
anyway; invalid lvalue. I don't know if that extends to user defined types without testing though. I have had people do things like const char* p = obj.getString().c_str()
where getString() returns a string by value. The pointer returned from c_str() is owned by the string, and it is freed as soon as the string goes out of scope, which in this case, is at the end of the expression. "p" then points to already freed memory. Compiler might be able to check with operator++(int) though, since it returns a temporary directly. Anyway, you should almost always be using pre-increment or decrement operators. They are often used interchangeably, often where the extra temporary introduced by post operators is not required. The compiler can often eliminate temporaries, but it is better not to introduce them in the first place.A function argument list is different from the actual comma operator, which has defined precedence and associativity. For a function argument list, I don't think the order of evaluation or associativity is defined or meaningful; comma is not an operator in an argument list. Calling a function with expressions that modify values can result in undefined behavior. |
|
|
|
|
|
|
|
|
|
|
Probably I am missing the point, but I seem to agree completely on all of this (including the part regarding the comma operator). Indeed, the order of evaluation of the arguments to a function call is not defined. And the comma in the argument list is not an operator. |
What associativity demands is that the expression should be evaluated like this: ( cout << i ) << (++i); , to which we are accustomed, and not like this: cout << ( i << (++i) ); , to which we don't have clear interpretation. EDIT: actually, we do have a clear interpretation :) How we evaluate the operands is still flexible. It can be done like this:
or like this:
, which arguably produces different result. The associativity rule is the same for both cases. |
cout << ++i
, (the ostream&) can not be resolved until it is returned from the first function. That is, I would expect it to execute something like this:
|
|
std::cout<<i<<++i;
std::cout.operator<<(i)
).
std::cout<<i<<++i
depends on the value of std::cout<<i
and of ++i
. The expression ++i
certainly does not require you to evaluate the result from std::cout.operator<<(i)
. The result of some expression is only necessary for evaluating those that contain it as sub-expression. But the order of evaluating the sub-expressions in an expression is unspecified.I believe jimc is correct here: std::cout<<i<<++i; You can't evalulate the ++i first because it depends on the result of the first function (std::cout.operator<<(i)). |
|
|
|
|
|
|
*pointer++ = *pointer | myByte;
*it++ =*it | mybyte;
, the sides of the equals can be evaluated in either order. In my opinion, this represents a massive, gaping flaw in C++ operator overloading. The standard should have guaranteed that the postincrement function was called after the statement was evaluated. *p++=*p|c;
{*p=*p|c;p++;}
if I may inject: *pointer++ = *pointer | myByte; For a pointer, p++ always == p. Therefore this will work as expected. |
|
|
For an iterator, ++ is a function, which can return whatever it wants to return. I don't have a C or C++ standards document, but I believe that in *it++ =*it | mybyte;, the sides of the equals can be evaluated in either order. In my opinion, this represents a massive, gaping flaw in C++ operator overloading. The standard should have guaranteed that the postincrement function was called after the statement was evaluated. *p++=*p|c; Should always be equivalent to: {*p=*p|c;p++;} But this isn't how it is, so the C++ standard completely destroys a basic rule of the original C semantics. Oh, how unfortunate. |
|
|
|
|