C ++ 17 секвенирование: постинкремент на левой стороне назначения - PullRequest
0 голосов
/ 11 октября 2018

Стандарт C ++ 17 пересмотрел определения порядка операций для языка C ++ с помощью правила , в результате которого :

в каждом простом выражении присваиванияE1 = E2 и каждое составное выражение присваивания E1 @ = E2, каждое вычисление значения и побочный эффект E2 секвенируются перед каждым вычислением значения и побочным эффектом E1

Однако при компиляции следующего кода вGCC 8.1 с -std=c++17 и -Wall

int v[] { 0,1,2,3,4,5,6,7 };
int *p0 = &v[0];
*p0++ = *p0 + 1;
cout << "v[0]: " << v[0] << endl;

Я получаю следующее предупреждение:

main.cpp:266:8: warning: operation on 'p0' may be undefined [-Wsequence-point]
     *p0++ = *p0 + 1;
      ~~^~

Выход:

v[0]: 1

И вопрос: является ли предупреждение ошибочным?

Ответы [ 2 ]

0 голосов
/ 28 марта 2019

[Я оставляю свой ответ ниже для справки, но дальнейшее обсуждение показало, что мой ответ ниже неполон и что его заключение в конечном итоге неверно.]

Стандарт C ++ 17 (черновик здесь ), [expr.ass], действительно читает:

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

Это звучит так же неправильно для меня, как и для вас.@ Барри не нравится ваш пример кода, поэтому, чтобы не отвлекать вопрос, я проверил альтернативный код:

#include <iostream>

namespace {
    int a {3};

    int& left()
    {
        std::cout << "in left () ...\n";
        return ++a;
    }

    int right()
    {
        std::cout << "in right() ...\n";
        return a *= 2;
    }
}

int main()
{
    left() = right();
    std::cout << a << "\n";
    return 0;
}

Вывод (с использованием GCC 6.3):

in left () ...
in right() ...
8

Считаете ли вы напечатанныйЕсли рассматривать сообщения или считать вычисленное значение 8, то выглядит, как будто операнд left был упорядочен до операнда right - что имеет смысл, поскольку эффективный машинный код

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

Я бы не согласился с @Barry.Возможно, вы обнаружили нетривиальную проблему со стандартом.Если у вас есть время, сообщите об этом.

ОБНОВЛЕНИЕ

@ SombreroChicken добавляет:

Это только потому, что GCC 6.3 не правильнореализовать C ++ 17 еще.Начиная с версии 7.1 и далее он оценивает сразу, как показано здесь .

Вывод:

in right() ...
in left () ...
6
0 голосов
/ 11 октября 2018

И вопрос: является ли предупреждение ошибочным?

Это зависит.

Технически, рассматриваемый код четко определен.Правая часть секвенирована перед левой частью в C ++ 17, тогда как до этого она была неопределенно секвенирована.И gcc правильно компилирует код, v[0] == 1 после этого назначения.

Однако, это также ужасный код, который не должен быть написан, поэтому, хотя конкретная формулировка предупреждения ошибочна, фактический дух предупрежденияКажется, хорошо для меня.По крайней мере, я не собираюсь подавать отчет об ошибке, и это не похоже на то, что разработчикам стоит потратить время на исправление.YMMV.

...