В некоторых случаях, таких как описанный, стандарт C ++ позволяет компиляторам обрабатывать конструкции любым способом, который их клиенты считают наиболее полезным, не требуя, чтобы поведение было предсказуемым. Другими словами, такие конструкции вызывают «неопределенное поведение». Однако это не означает, что такие конструкции должны быть «запрещены», поскольку стандарт C ++ явно отказывается от юрисдикции в отношении того, что «правильно» выполненным программам разрешено делать. Хотя я не знаю ни одного опубликованного документа Rationale для стандарта C ++, тот факт, что он описывает Undefined Behavior во многом подобно тому, как это делает C89, наводит на мысль, что предполагаемое значение похоже: «Неопределенное поведение дает разработчику лицензию, чтобы не перехватывать определенные программные ошибки, которые являются сложными. чтобы диагностировать.
Существует много ситуаций, когда наиболее эффективный способ обработки чего-либо включает в себя написание частей структуры, которые будут заботиться о нижестоящем коде, и в то же время исключать те, которые не будут заботиться о нижестоящем коде. Требование, чтобы программы инициализировали всех членов структуры, включая тех, которые ни о чем не заботятся, без необходимости мешало бы эффективности.
Кроме того, в некоторых ситуациях может оказаться наиболее эффективным, чтобы неинициализированные данные вели себя недетерминированным образом. Например, учитывая:
struct q { unsigned char dat[256]; } x,y;
void test(unsigned char *arr, int n)
{
q temp;
for (int i=0; i<n; i++)
temp.dat[arr[i]] = i;
x=temp;
y=temp;
}
если нижестоящий код не будет заботиться о значениях каких-либо элементов x.dat
или y.dat
чьи индексы не были перечислены arr
, код может быть оптимизирован для:
void test(unsigned char *arr, int n)
{
q temp;
for (int i=0; i<n; i++)
{
int it = arr[i];
x.dat[index] = i;
y.dat[index] = i;
}
}
Это повышение эффективности не было бы возможным, если бы программистам требовалось явно писать каждый элемент temp.dat
, включая те, которые не интересуют нижестоящие, до его копирования.
С другой стороны, есть некоторые приложения, в которых важно избежать возможности утечки данных. В таких приложениях может быть полезно иметь версию кода, которая оснащена инструментами для перехвата любой попытки скопировать неинициализированное хранилище, не обращая внимания на то, будет ли на него смотреть нисходящий код, или было бы полезно иметь гарантию реализации, что любое хранилище чье содержимое может быть пропущено, обнуляется или иным образом перезаписывается неконфиденциальными данными.
Из того, что я могу сказать, Стандарт C ++ не пытается сказать, что любое из этих поведений является достаточно более полезным, чем другое, чтобы оправдать его обязательство. По иронии судьбы, это отсутствие спецификации может быть направлено на облегчение оптимизации, но если программисты не могут использовать какие-либо слабые поведенческие гарантии, любая оптимизация будет сведена на нет.