Каким образом стандарт C++ ограничивает влияние неопределенного поведения, если таковое имеется? Например, в приведенном ниже коде от первого if, проверяющего undefined, поток управления ограничен следующим образом: путь then или путь else? Можно ли пропускать оба пути? Выполнить оба пути (потенциально параллельно)? Совершить безумный прыжок в середину второго if?
void f(int undefined) {
bool startNuclearWar = true;
if (undefined > 0) {
printf("True path\n");
startNuclearWar = false;
} else {
printf("False path\n");
startNuclearWar = false;
}
if (startNuclearWar) {
lauchMissles();
}
}
Возможный дубликат Неопределенное поведение и точки последовательности





Стандарт не имеет ограничений на UB. В тот момент, когда вы выполняете что-нибудь, который вызывает UB, стандарт ничего не гарантирует относительно того, что происходит.
Фактически, UB вступает в силу с момента, когда внешний ввод устанавливает программу на пути к чему-то, что в конечном итоге вызовет неопределенное поведение.
@SebastianRedl - неправда. UB может быть результатом ввода (например, ввод пользователя приводит к переполнению int в каком-либо последующем операторе), но это не означает, что UB вступает в силу с момента ввода. Ввод может повлиять на то, будет ли достигнут оператор с UB, но - до тех пор, пока какой-либо оператор не будет отображать UB, поведение каждого предыдущего оператора четко определено.
@Peter: N4727 [intro.abstract] p5: «Однако, если любое такое выполнение содержит неопределенную операцию, этот документ не налагает никаких требований на реализацию, выполняющую эту программу с этим входом (даже в отношении операций, предшествующих первой неопределенной операции)». UB работает в обратном направлении.
Хотя есть много ситуаций, когда было бы полезно иметь возможность «разделить» неопределенное поведение, и хотя это было бы недорого на многих платформах, люди, пишущие Стандарты, не проявили к этому особого интереса. Стандарт C11 предлагает Приложение L о «анализируемости», но не описывает ничего значимого, что реализация должна гарантировать, если определяет __STDC_ANALYZABLE__.
Тот факт, что целочисленное переполнение, например, является ограниченным неопределенным поведением, имел бы ограниченное применение без чистого способа гарантировать, что этот код подобен следующему:
int index = computeSomething();
if (index < 0 || index >= ARRAYSIZE) FatalError();
myArray[index]++;
будет использовать одно и то же значение для index при сравнении и поиске в массиве.
Многие реализации могут дешево предлагать множество полезных гарантий, помимо тех, которые требуются стандартом, особенно в областях приложения, где для программы было бы допустимо аварийное завершение при получении недопустимого ввода, но неприемлемо для нее позволить злонамеренно сконструированному вводу взять под контроль машина. К сожалению, в Стандарте не предусмотрены необходимые ловушки для эффективного использования этого преимущества (например, предоставление встроенной функции, которая могла бы принимать значение, которое может быть неопределенным, и выдавать значение, которое в худшем случае является неопределенным). Применение такой внутренней функции к значению в index в приведенном выше коде перед выполнением сравнения гарантирует, что даже в случае переполнения в computeSomething код гарантированно либо увеличит значение в массиве, либо заметит, что index недействителен. Поскольку ни одна операция не приведет к критическому неопределенному поведению, выполнение останется на рельсах.
In what way(s), if any, does the C++ standard limit the effect of undefined behavior?
Никак нет. Неопределенное поведение по своей природе является неопределенный, поэтому может произойти абсолютно что-нибудь. И как только что-то произошло неопределенный, с этого момента состояние программы будет неизвестный.
При этом в показанном вами коде нет неопределенного поведения. Все в коде имеет определенное поведение.
For instance, in the code below, from the first
ifinspectingundefinedis control flow constrained to follow either the then path or the else path?
Да.
Is it allowed to skip both paths?
Нет.
Execute both paths (potentially in parallel)?
Нет.
Take a wild jump into the middle of the second if?
Нет.
Если в каком-либо ранее выполненном коде возникло неопределенное поведение, то ответы на вопросы будут прямо противоположны тому, что дал yoi. ;-)
Фактически, состояние программы неизвестно назад во времени, чтобы учесть переупорядочение оптимизаций и других модификаций.
@Peter: даже если бы UB действительно возник, я бы не ожидал, что языковые конструкции, такие как if, перестанут работать так, как они определены для работы. Однако UB может повлиять на данные, с которым они работают. Если только UB не уничтожает память, которая содержит исполняемый код if.
Ни в коем случае.