2009-06-15 3 views
4

Рассмотрим следующий код:C++ оператор сдвига преимущество странность

typedef vector<int> intVec; 

intVec& operator<<(intVec& dst, const int i) { 
    dst.push_back(i); 
    return dst; 
} 
int intResult0() { 
    return 23; 
} 
int intResult1() { 
    return 42; 
} 

// main 
intVec v; 
v << intResult0() << intResult1(); 

Странно то, что компилятор генерирует код, который оценивает intResult1ПЕРЕДintResult0 (проверено с новейшей VC унд GCC). Зачем компилятору это делать? Таким образом, время между оценкой и использованием соответствующих значений (без необходимости) увеличивается (?), То есть 42 выбирается сначала, а затем возвращается последнему к вектору. Определяет ли стандарт C++?

+0

хех, я побежал в эту последнюю ночь с оператором + = T он сбивает меня с толку: чтение кода, который вы ожидаете, что intResult1 нужно назвать вторым, потому что он использует значение, возвращаемое intResult0 для его первого аргумента. – Dolphin

ответ

12

В соответствии с разделом 6.2.2 Страуструп:

Порядок оценки подвыражениям в выражении является не определено.

10

Это не имеет ничего общего с приоритетом.

В этом последнем утверждении нет точки последовательности, поэтому компилятор может свободно оценивать подвыражения в любом порядке, если предпочтение используется при объединении подвыражений.

Обратите внимание, что приоритет не определяет общий порядок оценки - он просто определяет, как будут объединены операнды выражения с несколькими операторами.

Например, в следующем выражении:

a() * b() + c() 

в какой-то момент, компилятор должен был бы оценить (a() * b()) перед добавлением в результате c(), но нет ничего, что говорит, что заказ каждый индивидуальные потребности вызова функции быть произведенным. Компилятор может легко решить сначала позвонить c(), нажать результат в стеке, а затем сделать все, что ему нужно, чтобы оценить выражение (a() * b()) (в этом случае он может решить сначала оценить b()).

Единственная роль, которую играет преимущество в том, что компилятор не допускается, чтобы оценить выражение, как:

a() * (b() + c()) 
14

Порядок оценки суб-выражений между двумя точками последовательности не определен.

Приведенный выше код является синтаксическим сахаром для:

v.operator<<(intResult0()).operator<<(intResult1()); 

Единственное ограничение компилятор имеет, является то, что он должен оценивать все параметры перед тем, как метод вызывается и соблюдать правила приоритета. Но до тех пор, пока он следует этим правилам, каждой реализации разрешено выбирать детали, и поэтому такой порядок может меняться между компиляторами.

В этом примере:

  • Так что вполне допустимо называть intResult1() перед intResult2().
  • Но intResult0() должна вызываться перед вызовом оператора < <() (слева)
  • и intResult1() должна вызываться перед вызовом оператора < <() (справа)
  • и оператор < <() (слева) должен быть вызван перед оператором < <() (справа)

Смотрите здесь для получения дополнительной информации:
What are all the common undefined behaviours that a C++ programmer should know about?

и

What are all the common undefined behaviours that a C++ programmer should know about?

2

Стандарт С ++, 5: 4

За исключением особо оговоренных случаев, порядок оценки операндов отдельных операторов и подвыражений отдельных выражений, и порядок , в котором побочные эффекты принимать место, является неопределенные

Смежные вопросы