Why does this code produce seemingly random behavior,
std::cout << ( thePointerIsGood = ( NULL != (aPointer = aFunctionThatReturnsAPointer(args)) ) );
when this multi-line version that does the same thing works just fine?
aPointer = aFunctionThatReturnsAPointer(args);
thePointerIsGood = (NULL != aPointer);
std::cout << thePointerIsGood;
I am capturing aPointer and thePointerIsGood because I use them later on in the code.
Update
The above actually works just fine. But I was able to reproduce some odd behavior with this program, and I’ve marked where the error occurs:
// Compiled with:
// gcc test.cpp -c -o test.o; gcc -lstdc++ test.o -o test
#include <iostream>
#include <cstdlib>
class
AClass
{ public
: // Operators ///////////////////////////////////////
; const bool operator== ( const int rhs ) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
}
;
class
AHelperClass
{ public
: // Functions //////////////////////////////////////////////////////
; static AClass* AFunctionThatReturnsAPointer ( int arg ) ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
}
;
const
bool
AClass::
operator==
( const int rhs )
{ return (rhs == 222); }
AClass*
AHelperClass::
AFunctionThatReturnsAPointer
( int arg )
{ return ( (arg == 777)
? new AClass
: NULL
)
;
}
int
main
( int argc
, char** argv
)
{ // Variables //////////////////
; AClass* aPointer ;
; bool thePointerIsGood ;
; bool theValueMatches ;
; int i ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
for ( i = 0
; i < 10
; i++
)
{ // First a good pointer
std::cout << ( ( thePointerIsGood = ( NULL != ( aPointer = AHelperClass::AFunctionThatReturnsAPointer(777) ) ) )
? "Y "
: "N "
)
<< ( (thePointerIsGood == true)
? "expected "
: "unexpected "
)
;
if ( !thePointerIsGood )
{ std::cout << std::endl; }
else
{ // This is where the error is, thanks to Peter for pointing it out
std::cout << ( (theValueMatches = ((*aPointer) == 222))
? "Y "
: "N "
)
<< ( (theValueMatches == true)
? "expected"
: "unexpected"
)
<< std::endl
;
}
delete aPointer;
// Now a NULL pointer
std::cout << ( ( thePointerIsGood = ( NULL != ( aPointer = AHelperClass::AFunctionThatReturnsAPointer(877) ) ) )
? "Y "
: "N "
)
<< ( (thePointerIsGood == false)
? "expected "
: "unexpected "
)
;
if ( !thePointerIsGood )
{ std::cout << std::endl; }
else
{ std::cout << ( (theValueMatches = ((*aPointer) == 222))
? "Y "
: "N "
)
<< ( (theValueMatches == true)
? "expected"
: "unexpected"
)
<< std::endl
;
}
delete aPointer;
}
return 0;
}
Which produces for me the following output (everything should say expected)
Y expected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
Y unexpected Y expected
N unexpected
My thought is that the following is undefined behaviour:
Because
theValueMatchesis both used and assigned to in the same expression, and it isn’t defined whether the assignment happens before or after the comparison totrue. It does surprise me if it seems to be nondeterministic, since you’d expect the compiler to pick one approach or another, although I observe that mine isn’t – I get the same output from the program each time, with quite a few unexpecteds in there.