Каково значение специального языка в стандарте для преобразования lvalue-в-значение для типов без знака с неопределенным значением

В стандарте C ++ 14 (n3797) раздел о преобразованиях lvalue в rvalue выглядит следующим образом (выделено мной):

4.1 Преобразование Lvalue в rvalue [conv.lval]

  1. Glvalue (3.10) нефункционального типа, не являющегося массивом T может быть преобразован в prvalue. Если T является неполным типом, программа, которая требует этого преобразования, плохо сформирована. Если T это тип, не относящийся к классу, тип prvalue — версия cv-unqualified T, В противном случае тип значения T,

  2. Когда преобразование lvalue в rvalue происходит в неоцененном операнде
    или его подвыражение (пункт 5) значение, содержащееся в
    указанный объект не доступен. Во всех остальных случаях результат
    Конверсия определяется по следующим правилам:

    • Если T является (возможно, cv-квалифицированным) std::nullptr_t тогда результат является константой нулевого указателя.
    • В противном случае, если T имеет тип класса, преобразование копирует-инициализирует временный тип T от glvalue и результат преобразования является prvalue для временного.
    • В противном случае, если объект, на который ссылается glvalue, содержит недопустимое значение указателя, поведение определяется реализацией.
    • В противном случае, если T является (возможно, квалифицированным cv) типом без знака, и объект, на который ссылается glvalue, содержит неопределенное значение, и этот объект не имеет автоматической длительности хранения, или glvalue был операндом унарного & оператор или он был привязан к ссылке, результатом является неопределенное значение.
    • В противном случае, если объект, на который ссылается glvalue, имеет неопределенное значение, поведение не определено.
    • В противном случае объект, обозначенный glvalue, является результатом prvalue.
  3. [Замечания: Смотри также 3.10]

Каково значение этого абзаца (выделено жирным шрифтом)?

Если бы этот параграф не был здесь, то ситуации, в которых он применяется, привели бы к неопределенному поведению. Обычно я ожидаю, что доступ к unsigned char Значение, пока оно имеет неопределенное значение, ведет к неопределенному поведению. Но с этим пунктом это означает, что

  • Если я не получаю доступ к значению символа, то есть я немедленно передаю его & или привязать его к ссылке, или
  • Если unsigned char не имеет автоматической продолжительности хранения,

тогда преобразование дает неопределенное значение, а не неопределенное поведение.

Правильно ли я пришел к выводу, что эта программа:

#include <new>
#include <iostream>

// using T = int;
using T = unsigned char;

int main() {
T * array = new T[500];
for (int i = 0; i < 500; ++i) {
std::cout << static_cast<int>(array[i]) << std::endl;
}
delete[] array;
}

четко определен стандартом и должен выводить последовательность из 500 неопределенных целых чисел, тогда как та же программа, в которой T = intбудет иметь неопределенное поведение?


IIUC, одна из причин сделать UB для чтения вещей с неопределенными значениями, заключается в том, чтобы оптимизатор мог агрессивно удалять мертвые хранилища. Таким образом, этот абзац может означать, что соответствующий компилятор не может делать столько оптимизации при работе с unsigned char или массивы unsigned char,

Предполагая, что я правильно понимаю, в чем смысл этого правила? Когда полезно читать unsigned char которые имеют неопределенные значения и получают неопределенные результаты вместо UB? У меня такое чувство, что, если они приложат столько усилий для разработки этой части правила, у них будет мотивация помочь определенным примерам кода, которые им интересны, или будут соответствовать какой-то другой части стандарта, или упростить какую-то другую проблему. , Но я понятия не имею, что это может быть.

8

Решение

Во многих ситуациях код записывает некоторые части PODS или массива без записи всего, а затем использует такие функции, как memcpy или же fwrite скопировать или записать всю вещь, не обращая внимания на то, какие части имеют присвоенные значения, а какие нет. Хотя в коде C ++ не очень распространено использование байтовых операций для копирования или записи содержимого агрегатов, возможность сделать это является фундаментальной частью языка. Требование, чтобы программа записывала определенные значения во все части объекта, включая те, которые ни о чем не будут «заботиться», без необходимости снизит эффективность.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]