Во-первых, некоторые определения из стандарта C ++ 03:
1.3.5 поведение, определяемое реализацией
Поведение, для правильно сформированной программы, построения и правильных данных, которое зависит от реализации и что каждая реализация должна документировать
1.3.12 неопределенное поведение
Поведение, которое может возникнуть при использовании ошибочной программной конструкции или ошибочных данных, к которым настоящий международный стандарт не предъявляет никаких требований. Неопределенное поведение также может ожидаться, когда в этом международном стандарте опущено описание любого явного определения или поведения.
1.3.13 неуточненное поведение
Поведение для правильно сформированной программы, которая строит и корректирует данные, которые зависят от реализации. Реализация не обязана документировать, какое поведение происходит.
Несмотря на то, что неопределенное поведение можно назвать UB, я никогда не видел этого, и UB всегда означает неопределенное поведение. Во всем стандарте есть утверждения, похожие на "выполнение X неопределено поведение ", но иногда вы сталкиваетесь с делом, которое просто не охвачено.
Другими словами, если у вас есть какое-либо неопределенное поведение, тогда все ставки выключены . Что касается стандарта, ваша программа может делать все, что угодно, от приглашения свекрови на выходные SuperBowl до nethack . Из-за природы UB вы не можете проверить это, и вы не можете ожидать никакой помощи от компилятора. (Хотя для некоторых тривиальных распространенных ошибок компиляторы обычно производят диагностику.)
Обычно что-то определяется как UB, потому что это логически не имеет смысла (например, доступ к массиву вне границ), но также часто, потому что это потребует, чтобы реализация выполняла слишком много работы, чтобы предотвратить - часто во время выполнения. Помните, что C ++ является производным от C, и способность создавать высокооптимизированные программы является основной целью обоих языков. С этой целью языки обращаются к программисту, чтобы убедиться в правильности кода в этих ситуациях, что связано с принципом «вы не платите за то, что не используете».
Итак, наконец, UB - это плохо, очень плохо; избежать этого любой ценой. Однако трудная часть UB не знает, что это такое и при каких обстоятельствах это происходит; сложная часть распознавания, когда вы вызываете UB. Например:
std::string s = "abc";
char& c = s[0];
cout.write(s.data(), s.length());
c = '-';
Выглядит вполне разумно, верно? Нет, это UB, но будет работать так, как вы ожидаете, во всех популярных реализациях.