Разница между С++ 14 и С++ 17 в использовании: '* p++ = * p'

При написании некоторого кода я столкнулся с проблемой, когда установленные мной значения были установлены неправильно. В конце концов я обнаружил линию преступника и во время тестирования обнаружил, что она ведет себя по-разному на C++ 14 и C++ 17. Код выглядит следующим образом:

#include <stdio.h>
#include <cstdint>
#include <cstring>

int main()
{
    uint8_t *p = new uint8_t[3];
    memset(p, 0x00, 1);
    p++;
    memset(p, 0xF0, 1);
    p++;
    memset(p, 0xFF, 1);
    p--;
    p--;

    // This line in particular
    *p++ = *p;

    *p++ = 0x0F;

    p--;
    p--;

    printf("Position 0 has value %u\n", *p);
    p++;
    printf("Position 1 has value %u\n", *p);
    p++;
    printf("Position 2 has value %u\n", *p);

    return 0;
}

На C++ 14 он печатает:

Position 0 has value 240
Position 1 has value 15
Position 2 has value 255

И на C++ 17 он печатает:

Position 0 has value 0
Position 1 has value 15
Position 2 has value 255

Мне любопытно, почему он действует по-разному в разных версиях C++. Похоже, что C++ 14 правая часть *p присвоения вычисляется после ++. Это изменилось? И если ++ имеет приоритет, почему это не происходит до разыменования в левой части оператора присваивания?

Ответ 1

Раньше чтение и запись в переменную (через постинкремент) имели неопределенное поведение, потому что = не вводил точку последовательности. Вы могли бы получить либо поведение (или ничего, либо взрывы) в С++ 14.

Теперь для этого случая определен порядок секвенирования, и ваши результаты в С++ 17 надежны.

Хотя это все-таки плохо, непонятный код, который не должен быть написан!