Объясни, что такое неопределённое поведение
Вопрос
Объясните интервьюеру, что такое неопределённое поведение в C++, почему оно существует и чем опасно.
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
UB: стандарт не накладывает никаких требований на программу
Даёт свободу оптимизатору: он считает, что UB не происходит
Примеры: переполнение знакового, выход за границы, use-after-free, гонка данных
Проявления меняются от флагов оптимизации и компилятора, «работает» ничего не доказывает
Отличие от implementation-defined и unspecified
Как ловить: санитайзеры, предупреждения, тесты под -O2
Что могут спросить следом
- Приведите пример, где оптимизатор удаляет проверку из-за UB.
- Почему не сделать переполнение знакового определённым?
- Как UB связано с гонками данных?
Разбор
Неопределённое поведение означает, что стандарт не накладывает на программу никаких требований: результат может быть любым, и не только в той строке, где UB произошло. Оно существует ради производительности и переносимости: компилятору не нужно вставлять проверки границ, переполнений и нулевых указателей, а оптимизатор вправе считать, что корректная программа UB не содержит. Например, из-за UB знакового переполнения проверка x + 1 < x сворачивается в false, а цикл for (int i = 0; i < n; ++i) можно векторизовать, не думая о переполнении i. Типичные источники: переполнение знакового, выход за границы, разыменование висячего указателя, чтение неинициализированной переменной, нарушение strict aliasing и гонка данных. Опасность в том, что баг может не проявляться при -O0 и проявиться при -O2 или в новой версии компилятора. Implementation-defined и unspecified, в отличие от UB, оставляют программу корректной. Ловлю UB санитайзерами address и undefined, предупреждениями и прогоном тестов в релизной сборке.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Ещё по теме «Типы и неопределённое поведение»
- Порядок байтов: перевернуть uint32 и посчитать единицы
- Умножение int64 с проверкой переполнения
- Середина двух int64 без переполнения
- std::bit_cast
- Что C++20 изменил для знаковых целых
- Размер long на Windows и Linux
- Сопоставьте пример и вид поведения
- Почему проверка x + 1 < x исчезла