Почему знаковое переполнение это UB, ведь с C++20 всегда используется 2's complement, а значит результат однозначно определен?
Ответ До C++20 стандарт языка допускал три способа для представления знаковых целых чисел: Signed magnitude Ones' complement Two’s complement Начиная с C++20 для представления целых чисел может использоваться только two’s complement. Автором этого изменения является некто Jean François Bastien (e-mail: [email protected]). Предлагаемые изменения в конкретных пунктах стандарта языка, мотивацию и обсуждения изменений вы можете найти в документе P0907R4. Помимо всего прочего, товарищ JF Bastien предлагал в случае переполнения знакового целого при выполнении арифметических операций усекать результат по правилам модулярной арифметики (т.е. поступать также как и для беззнаковых величин). Но встретил сильное сопротивление со стороны комитета по стандартизации: This paper proposes the following: ... Status-quo If a signed operation would naturally produce a value that is not within the range of the result type, the behavior is undefined. The author had hoped to make this well-defined as wrapping (the operations produce the same value bits as for the corresponding unsigned type), but WG21 had strong resistance against this.
Основные возражения комитета таковы: Проблемы производительности. Оптимизатор не сможет предполагать, что переполнение никогда не происходит, и выполнять оптимизации, вытекающие из этого предположения. Возникают сложности при реализации таких штук как санитайзеры. Google считает, что 90% всех переполнений является багом, поэтому модулярная арифметика для знаковых целых не нужна. Вопрос на stackoverflow.com с примерами оптимизаций, когда оптимизатор считает, что переполнения при знаковой арифметике не возможны: Is there some meaningful statistical data to justify keeping signed integer arithmetic overflow undefined?