Непредсказуемое булево сравнение c ++ - PullRequest
1 голос
/ 18 марта 2012

Почему этот код производит на первый взгляд случайное поведение,

std::cout << ( thePointerIsGood = ( NULL != (aPointer = aFunctionThatReturnsAPointer(args)) ) );

когда эта многострочная версия, которая делает то же самое, работает нормально?

aPointer = aFunctionThatReturnsAPointer(args);
thePointerIsGood = (NULL != aPointer);
std::cout << thePointerIsGood;

Я собираю aPointer и thePointerIsGood, потому что я использую их позже в коде.

Обновление

Выше на самом деле работает просто отлично. Но я смог воспроизвести некоторые странные действия с этой программой, и я отметил, где возникает ошибка:

// 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;
  }

, который выдает для меня следующий результат (все должно быть ожидаемым)

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  

Ответы [ 2 ]

1 голос
/ 19 марта 2012

Я думаю, что следующее неопределенное поведение:

std::cout << ( (theValueMatches = ((*aPointer) == 222))
                            ? "Y  "
                            : "N  "
                            )
                         << ( (theValueMatches == true)
                            ? "expected"
                            : "unexpected"
                            )
                         << std::endl
                         ;

Поскольку theValueMatches используется и присваивается в одном выражении, и не определено, происходит ли присвоение до или послесравнение с true.Меня действительно удивляет, если он кажется недетерминированным, так как вы ожидаете, что компилятор выберет тот или иной подход, хотя я заметил, что мой - нет - я получаю один и тот же вывод из программы каждый раз, с довольно большим количеством неожиданностейтам.

0 голосов
/ 19 марта 2012

Нет гарантии в порядке оценки выражений. Если у вас есть:

x << (a = b) << a;

Тогда «а» может быть вычислено до «(a = b)»

...