C ++ странность приоритета оператора сдвига - PullRequest
4 голосов
/ 15 июня 2009

Рассмотрим следующий код:

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 ++ диктует это?

Ответы [ 4 ]

14 голосов
/ 15 июня 2009

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

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

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

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

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

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

Смотрите здесь для получения дополнительной информации:
Каковы все распространенные неопределенные поведения, о которых должен знать программист C ++?

и

Каковы все распространенные неопределенные поведения, о которых должен знать программист C ++?

12 голосов
/ 15 июня 2009

Согласно разделу Страуструпа 6.2.2:

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

10 голосов
/ 15 июня 2009

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

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

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

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

a() * b() + c()

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

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

a() * (b() + c())
2 голосов
/ 15 июня 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...