Висячие ссылки и поведение undefined

Предположим, что оборванная ссылка x. Это поведение undefined просто написать

&x;

или даже

x;

?

Ответ 1

Что делает использование недопустимого объекта (ссылка, указатель, что угодно) 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, чтобы он мог выработать результат.

Ответ 2

Прежде всего, очень интересный вопрос.

Я бы сказал, что это поведение undefined, предполагая, что "оборванная ссылка" означает, что "связанное со временем время жизни объекта закончилось, и хранилище, занятое объектом, было повторно использовано или выпущено". Я основываю свои рассуждения на следующих стандартных постановлениях:

3.8 §3:

Свойства, приписываемые объектам в рамках настоящего международного стандарта, применяются только к данному объекту в течение его жизни. [Примечание: в частности, до начала жизни объекта и после его срока службы существуют существенные ограничения на использование объекта, как описано ниже...]

Все случаи, описанные ниже, относятся к

До того, как срок службы объекта запустился, но после хранения, в котором будет заниматься объект, выделено38 или, после того, как срок жизни объекта закончился и перед хранилищем, которое занимал объект, повторно или выпущено

1.3.24: undefined поведение

для которого настоящий международный стандарт не предъявляет никаких требований [Примечание: поведение undefined можно ожидать, если в этом Международном стандарте отсутствует явное определение поведение или когда программа использует ошибочную конструкцию или ошибочные данные....]

Я применяю следующий цикл мыслей к приведенным выше цитатам:

  • Если стандарт не описывает поведение для ситуации, то поведение undefined.
  • Стандарт описывает только поведение объектов в течение их жизни и несколько особых случаев вблизи начала и конца их жизни. Ни одно из них не относится к нашей обманутой ссылке.
  • Следовательно, использование ссылки danling каким-либо образом не имеет поведения, предписанного стандартом, поэтому поведение undefined.

Ответ 3

Предположим, что 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. Так что это тоже ОК.