Подтвердить что ты не робот

Неопределенность точки последовательности, поведение undefined?

Сегодня я столкнулся с некоторым кодом, который демонстрирует различное поведение на clang++ (3.7- git), g++ (4.9.2) и Visual Studio 2013. После некоторого сокращения Я придумал этот фрагмент, который подчеркивает проблему:

#include <iostream>
using namespace std;

int len_ = -1;

char *buffer(int size_)
{
    cout << "len_: " << len_ << endl;
    return new char[size_];
}

int main(int argc, char *argv[])
{
    int len = 10;
    buffer(len+1)[len_ = len] = '\0';
    cout << "len_: " << len_ << endl;
}

g++ (4.9.2) дает следующий результат:

len_: -1
len_: 10

Итак, g++ оценивает аргумент в буфере, а затем сам буфер (..) и после этого вычисляет аргумент индекса оператору массива. Интуитивно это имеет смысл для меня.

clang (3.7- git) и Visual Studio 2013 дают:

len_: 10
len_: 10

Я полагаю, что clang и VS2013 оценивают все возможное до того, как он распадается на буфер (..). Это делает меня менее интуитивным.

Я предполагаю, что суть моего вопроса в том, является ли это явным примером поведения undefined.

Изменить: спасибо за очистку этого, а неуказанное поведение - это термин, который я должен был использовать.

4b9b3361

Ответ 1

Это неуказанное поведение, len_ = len неопределенно упорядочено относительно выполнения тела buffer(), что означает, что один будет выполняться перед другим, но не указывается, какой порядок, но есть заказ, поэтому оценки не могут перекрываться, поэтому поведение undefined. Это означает, что gcc, clang и Visual Studio все правильно. С другой стороны, нецелесообразные оценки допускают перекрывающиеся оценки, которые могут привести к поведению undefined, как указано ниже.

Из черновик стандартного С++ 11 1.9 [intro.execution]:

[...] Каждая оценка в вызывающей функции (включая другие вызовы функций), которая иначе не является секвенированные до или после выполнения тела вызываемой функции, неопределенно секвенированы с в отношении выполнения вызываемой функции .9 [...]

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

[...] Оценки A и B неопределенно секвенированы, когда либо A секвенируется до того, как B или B секвенированы до A, но не указано, что. [Примечание: неопределенно секвенированные оценки не могут пересекаться, но либо могут быть выполнены в первую очередь. -end note]

который отличается от неощутимых оценок:

[...] Если A не секвенирован раньше B и B не секвенированы до A, тогда A и B не подвержены влиянию. [Примечание: Выполнение непересекающихся оценки могут перекрываться. -end note] [...]

что может привести к поведению undefined (внимание мое):

За исключением случаев, когда отмечено, оценки операндов отдельных операторов и подвыражений отдельных выражения не подвержены влиянию. [Примечание: в выражении, которое оценивается более одного раза во время выполнения программы, необнаружированные и неопределенно упорядоченные оценки ее подвыражений не должны быть последовательно выполнялись в разных оценках. -end note] Вычисления значений операндов оператор упорядочивается перед вычислением значения результата оператора. Если побочный эффект скаляра объект не влияет на какой-либо другой побочный эффект на один и тот же скалярный объект или вычисление значения используя значение одного и того же скалярного объекта, поведение undefined [...]

Pre С++ 11

Pre С++ 11 порядок оценки подвыражений также не указан, но он использует точки последовательности в отличие от упорядочения. В этом случае есть точка последовательности при входе функции и выходе функции, которая гарантирует, что поведение undefined отсутствует. Из раздела 1.9:

[...] Точки последовательности при вводе функции и выходе функции (как описано выше) являются функциями вызовов функций, которые оцениваются, независимо от синтаксиса выражения, которое вызывает функция может быть.

Отклонение порядка оценки

Различные варианты, сделанные каждым компилятором, могут казаться неинтуитивными в зависимости от вашей перспективы и ожиданий. Вопрос о прибивании порядка оценки является предметом EWG issue 158: N4228 Оценка оценки экспансии для Idiomatic С++, который рассматривается для С++ 17, но кажется противоречивым на основе реакции на опрос по этому вопросу. В этом документе рассматривается более сложный случай из 4-го издания "Язык программирования С++" . Который показывает, что даже те, у кого большой опыт работы на С++, могут сработаться.

Ответ 2

Ну, нет, это не случай поведения undefined. Это случай неуказанного поведения.

Не определено, будет ли выражение len_ = len оцениваться до или после buffer(len+1). Из выведенного вами результата g++ сначала оценивает buffer(len+1), а clang сначала оценивает len_ = len.

Обе возможности верны, так как порядок оценки этих двух подвыражений неуточнен. Оба выражения будут оценены (поэтому поведение не может считаться undefined), но стандарт не определяет порядок.