Ответ 1
Возможны два случая, в зависимости от того, началось ли время жизни объекта. Это определяется первым правилом в [basic.life]
:
Время жизни объекта или ссылки является временем выполнения объекта или ссылки. Говорят, что объект имеет непустую инициализацию, если он относится к классу или агрегату, и он или один из его подобъектов инициализируется конструктором, отличным от тривиального конструктора по умолчанию. [Примечание. Инициализация тривиальным конструктором copy/move является пустой функцией инициализации. - end note] Время жизни объекта типа
T
начинается, когда:
- хранения с надлежащим выравниванием и размером для типа
T
, и- если объект имеет незапамятную инициализацию, его инициализация завершена, за исключением того, что если объект является членом объединения или его подобъектом, его время жизни начинается только тогда, когда этот член объединения является инициализированным членом в объединении или как описано в (
[class.union]
).
-
Объекты класса или совокупного типа
std::string s = std::to_string(s.size()); // UB
В этом случае время жизни объекта не начинается до завершения инициализации, поэтому это правило в
[basic.life]
применимо:Аналогично, до того, как началось время жизни объекта, но после того, как хранилище, которое будет занимать объект, было выделено или, после того, как срок жизни объекта закончился и перед хранилищем, которое объект занят, повторно используется или выпущен, любое значение gl, которое ссылается на исходный объект может использоваться, но только ограниченным образом. Для объекта, находящегося в процессе строительства или уничтожения, см. (
[class.cdtor]
). В противном случае такое значение glvalue относится к выделенному хранилищу, и использование свойств glvalue, которые не зависят от его значения, хорошо определено. Программа имеет неопределенное поведение, если:- glvalue используется для доступа к объекту или
- glvalue используется для вызова нестатической функции-члена объекта или
- glvalue привязан к ссылке на виртуальный базовый класс или
- glvalue используется как операнд
dynamic_cast
или как операндtypeid
.
В этом примере glvalue используется для доступа к нестационарному члену, что приводит к неопределенному поведению.
-
Объекты примитивного типа
int i = (i=0); // ok int k = (k&0); // UB
Здесь, хотя есть инициализатор, инициализация не может быть непустой из-за типа. Таким образом, время жизни объекта запустилось, и приведенное выше правило не применяется.
Тем не менее, существующее значение в объекте неопределенно (если объект не имеет статической продолжительности хранения, и в этом случае статическая инициализация дает ему значение нуля). Значение gl, относящееся к объекту с неопределенным значением, никогда не должно подвергаться преобразованию lvalue-to-rvalue. Таким образом, разрешены операции "только для записи", но большинство 1 операций, считывающих неопределенное значение, приводят к неопределенному поведению.
Соответствующее правило находится в
[dcl.init]
:Если для объекта не задан инициализатор, объект инициализируется по умолчанию. Когда хранилище для объекта с автоматической или динамической продолжительностью хранения получается, объект имеет неопределенное значение, и если для объекта не выполняется инициализация, этот объект сохраняет неопределенное значение до тех пор, пока это значение не будет заменено. [Примечание. Объекты со статикой или длительностью хранения потоков ноль-инициализируются, см. (
[basic.start.static]
). - конечная нота]Если неопределенное значение создается путем оценки, поведение не определено, за исключением следующих случаев:
-
Если неопределенное значение беззнакового типа узкого символа или типа
std::byte
создается путем оценки:- второй или третий операнд условного выражения,
- правый операнд запятой,
- операнд приведения или преобразование в неподписанный узкосимвольный тип или
std::byte
type или - выражение с отбрасываемой величиной,
то результатом операции является неопределенное значение.
- Если неопределенное значение беззнакового типа узкого символа или типа
std::byte
создается путем оценки правильного операнда простого оператора присваивания, первым операндом которого является lvalue беззнакового узкого символьного типа или типа std :: byte, неопределенное значение заменяет значение объекта, на которое ссылается левый операнд. - Если неопределенное значение беззнакового типа узкого символа создается путем вычисления выражения инициализации при инициализации объекта беззнакового узкого символьного типа, этот объект инициализируется неопределенным значением.
- Если неопределенное значение беззнакового типа узкого символа или типа
std::byte
создается путем оценки выражения инициализации при инициализации объекта типаstd::byte
, этот объект инициализируется неопределенным значением.
-
1 Существует узкое исключение для использования типов символов для копирования неопределенных значений, что делает целевое значение также неопределенным. Значение по-прежнему не может использоваться в других операциях, таких как побитовые операторы или арифметические операции.