Предположим, что оборванная ссылка x
. Это поведение undefined просто написать
&x;
или даже
x;
?
Предположим, что оборванная ссылка x
. Это поведение undefined просто написать
&x;
или даже
x;
?
Что делает использование недопустимого объекта (ссылка, указатель, что угодно) undefined поведение является преобразованием lvalue-to-rvalue (§4.1):
Если объект, к которому относится glvalue, не является объектом типа T и не является объектом типа, производного от T, или если объект не инициализирован, программа, которая требует этого преобразования, имеет поведение undefined.
Предполагая, что мы не перегружали operator&
, унарный оператор &
принимает значение lvalue в качестве своего операнда, поэтому никакого преобразования не происходит. Наличие только идентификатора, как и в x;
, также не требует преобразования. Вы получите только undefined поведение, когда ссылка используется как операнд в выражении, ожидающем, что операнд будет значением rvalue, что имеет место для большинства операторов. Дело в том, что выполнение &x
фактически не требует доступа к значению x
. Преобразование Lvalue-to-rvalue происходит с теми операторами, которым необходимо получить доступ к его значению.
Я считаю, что ваш код хорошо определен.
Когда operator&
перегружено, выражение &x
преобразуется в вызов функции и не подчиняется правилам встроенных операторов, вместо этого оно следует правилам вызова функции. Для &x
вызов функции перевода означает либо x.operator&()
, либо operator&(x)
. В первом случае преобразование lvalue-to-rvalue будет происходить на x
, когда используется оператор доступа к члену класса. Во втором случае аргумент operator&
будет инициализирован с помощью x
(как в T arg = x
), а поведение этого зависит от типа аргумента. Например, в случае, если аргумент является ссылкой lvalue, поведение undefined отсутствует, поскольку преобразование lvalue-to-rvalue не выполняется.
Поэтому, если operator&
перегружен для типа x
, код может быть или не быть корректным, в зависимости от вызова функции operator&
.
Можно утверждать, что унарный оператор &
полагается, что существует хотя бы некоторая допустимая область хранения, у которой есть адрес:
В противном случае, если тип выражения
T
, результат имеет тип "указатель наT
" и является значением prvalue, которое является адресом назначенного объекта
И объект определяется как область хранения. После уничтожения объекта, который упоминается, эта область хранения больше не существует.
Я предпочитаю полагать, что это приведет только к поведению undefined, если к нему действительно обратился недопустимый объект. Ссылка все еще считает, что она ссылается на какой-то объект, и он может с радостью указать адрес, даже если он не существует. Тем не менее, это, по-видимому, некорректная часть стандарта.
В качестве примера поведения undefined рассмотрим x + x
. Теперь мы попали в другую нечеткую часть стандарта. Категория значений операндов +
не указана. Как правило, из § 5/8 вытекает, что если он не указан, то он ожидает значения:
Всякий раз, когда выражение glvalue появляется как операнд оператора, ожидающего prvalue для этого операнда, значение lvalue-to-rvalue (4.1), массив-указатель (4.2) или функция-to-pointer (4.3) стандартные преобразования применяются для преобразования выражения в prvalue.
Теперь, поскольку x
является lvalue, требуется преобразование lvalue-to-rval, и мы получаем поведение undefined. Это имеет смысл, потому что добавление требует доступа к значению x
, чтобы он мог выработать результат.
Прежде всего, очень интересный вопрос.
Я бы сказал, что это поведение undefined, предполагая, что "оборванная ссылка" означает, что "связанное со временем время жизни объекта закончилось, и хранилище, занятое объектом, было повторно использовано или выпущено". Я основываю свои рассуждения на следующих стандартных постановлениях:
3.8 §3:
Свойства, приписываемые объектам в рамках настоящего международного стандарта, применяются только к данному объекту в течение его жизни. [Примечание: в частности, до начала жизни объекта и после его срока службы существуют существенные ограничения на использование объекта, как описано ниже...]
Все случаи, описанные ниже, относятся к
До того, как срок службы объекта запустился, но после хранения, в котором будет заниматься объект, выделено38 или, после того, как срок жизни объекта закончился и перед хранилищем, которое занимал объект, повторно или выпущено
1.3.24: undefined поведение
для которого настоящий международный стандарт не предъявляет никаких требований [Примечание: поведение undefined можно ожидать, если в этом Международном стандарте отсутствует явное определение поведение или когда программа использует ошибочную конструкцию или ошибочные данные....]
Я применяю следующий цикл мыслей к приведенным выше цитатам:
Предположим, что x
был инициализирован действительным объектом, который был затем уничтожен, применяется §3.8/6:
Аналогично, до того, как началось время жизни объекта, но после того, как хранилище, которое будет занимать объект, было выделено или, после того, как срок жизни объекта закончился и перед хранилищем, которое объект занят, повторно используется или выпущен, любое значение glvalue который относится к исходному объекту, но может использоваться только ограниченным образом. По строительству или разрушению объекта см. 12.7. В противном случае такое значение glvalue относится к выделенному хранилищу (3.7.4.2) и , используя свойства glvalue, которые не зависят от его значения. Программа имеет поведение undefined, если:
- преобразование lvalue-to-rvalue (4.1) применяется к такому glvalue,
- glvalue используется для доступа к нестатическому элементу данных или вызова нестатической функции-члена из объект или
- glvalue привязан к ссылке на виртуальный базовый класс (8.5.3) или
- glvalue используется как операнд dynamic_cast (5.2.7) или как операнд typeid.
Итак, простое определение адреса хорошо определено и (ссылаясь на соседние абзацы) может даже быть продуктивно использовано для создания нового объекта вместо старого.
Что касается того, что вы не берете адрес и просто пишете x
, это действительно ничего не делает, и это правильное подвыражение &x
. Так что это тоже ОК.