Что происходит, когда ссылка C++ оставляет свой объем?

Если я интерпретирую ссылки C++ правильно, они похожи на указатели, но с гарантируемой целостностью данных (никакой ПУСТОЙ УКАЗАТЕЛЬ, нет (интервал*) 0x12345). Но что происходит, когда объем ссылочного объекта является покрытым листьями? Если не будет никакого включенного волшебства (и вероятно это не), то ссылочный объект будет уничтожен за моей спиной.

Я записал часть кода для проверки этого:

#include <iostream>
using namespace std;

class A {
public:
        A(int k) { _k = k; };
        int get() { return _k; };
        int _k;
};

class B {
public:
        B(A& a) : _a(a) {}
        void b() { cout << _a.get(); }
        A& _a;
};

B* f() {
        A a(10);
        return new B(a);
}

int main() {
        f()->b();
}

_k переменная экземпляра была вставлена для проверки существования стекового фрейма.

Это удивительно не делает segfault и вместо этого печатает '10' правильно, в то время как я предполагаю это A выделяется на стеке и том стековом фрейме f() будет перезаписан, по крайней мере, cout<< звонить.

21
задан whitequark 22 June 2018 в 15:11
поделиться

2 ответа

это неопределенное поведение, и вам просто повезло, что память для a еще не была использована для чего-то другого. В более сложном сценарии вы почти наверняка получите мусор. На моей машине я получаю случайный мусор с этим кодом. Для меня это вероятно потому, что я использую 64-битную машину, которая использует соглашение о вызове регистров. Регистры используются повторно гораздо чаще, чем основная память (в идеале...).

Итак, чтобы ответить на ваш вопрос "что происходит". Ну, в этом сценарии ссылка, скорее всего, не более чем ограниченный указатель с более дружественным синтаксисом :-). Под капотом хранится адрес a. Позже объект a выходит из области видимости, но ссылка объекта B на этот a не будет "волшебным образом" обновлена, чтобы отразить это. Следовательно, теперь у вас есть недопустимая ссылка.

Использование этой недопустимой ссылки приведет практически к чему угодно, иногда к сбоям, иногда просто к неработающим данным.


EDIT: Благодаря Omnifarious, я подумал об этом. В c++ есть правило, которое в основном говорит, что если у вас есть const ссылка на временную, то время жизни временной по крайней мере столько же, сколько и const ссылка. В связи с этим возник новый вопрос.

EDIT: Перемещено в отдельный вопрос для интересующихся (const ссылка на временную странность)

29
ответ дан 29 November 2019 в 20:51
поделиться

В языке C++ время жизни объекта, с которым связана ссылка, никак не связано со временем жизни самой ссылки, за единственным исключением (см. ниже).

Если объект уничтожается раньше, чем ссылка, то ссылка становится недействительной (как зависший указатель). Любые попытки получить доступ к этой ссылке приводят к неопределенному поведению. Именно это и происходит в вашем примере.

Если ссылка заканчивает свое существование раньше, чем объект, то... ну, ничего не происходит. Ссылка исчезает, объект продолжает жить.

Единственное исключение, о котором я говорил выше, - это когда ссылка const инициализируется немедленным временным объектом. В этом случае время жизни временного объекта привязывается к времени жизни ссылки. Когда ссылка умирает, объект умирает вместе с ней

{
   const std::string& str = "Hello!"; 
   // A temporary `std::string` object is created here...
   ...
   // ... and it lives as long as the reference lives
   ...
} // ... and it dies here, together with the reference

P.S. Вы неправильно используете термин scope. Область видимости - это область видимости идентификатора. Область видимости сама по себе не имеет никакого отношения к времени жизни объекта. Когда что-то "выходит из области видимости" в общем случае это что-то не уничтожается. Это популярное заблуждение - использовать формулировку "покидает область видимости" для обозначения точки уничтожения объекта.

8
ответ дан 29 November 2019 в 20:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: