Что происходит, когда ссылка на С++ оставляет эту область видимости?
Если я правильно интерпретирую ссылки на С++, они похожи на указатели, но с гарантированной целостностью данных (нет NULL, no (int *) 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<<
.
Ответы
Ответ 1
это поведение undefined, и вам просто повезло, что память для a
еще нигде не использовалась. В более сложном сценарии вы почти наверняка получите мусор. На моей машине я получаю случайный мусор с этим кодом. Для меня это, вероятно, потому, что я использую 64-битную машину, которая использует соглашение о вызове регистра. Регистры повторно используются гораздо чаще, чем основная память (в идеале...).
Итак, чтобы ответить на ваш вопрос "что происходит". В этом случае ссылка скорее всего будет немного больше, чем ограниченный указатель с более дружественным синтаксисом:-). Под капотом сохраняется адрес a
. Позже объект a
выходит за пределы области видимости, но ссылка объекта B
на a
не будет обновляться автоматически, чтобы отразить это. Следовательно, теперь у вас есть неверная ссылка.
Использование этой недопустимой ссылки даст почти что-нибудь, иногда сбой, а иногда и только двухъядерные данные.
EDIT: Благодаря Omnifarious, я думал об этом. В С++ есть правило, которое в основном говорит о том, что если у вас есть ссылка const на временную, то время жизни временного не меньше длины ссылки const. Что ввело новый вопрос.
РЕДАКТИРОВАТЬ: Переместился на отдельный вопрос для заинтересованных (ссылка const на временную нечетность)
Ответ 2
В языке С++ время жизни объекта, к которому привязана ссылка, никак не привязано к времени жизни самой ссылки, с единственным исключением (см. ниже).
Если объект разрушен до ссылки, ссылка становится недействительной (например, указатель висячего). Любые попытки доступа к этой ссылке приводят к поведению undefined. Это то, что происходит в вашем примере.
Ссылка заканчивает свое время жизни до того, как объект делает, тогда... ну, ничего не происходит. Ссылка исчезает, объект продолжает жить.
Единственное исключение, о котором я говорил выше, - это когда инициализируется ссылка на константу с помощью временного временного объекта. В этом случае время жизни временного объекта привязывается к времени жизни ссылки. Когда эталонная матрица умирает, объект умирает с ней
{
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. Область видимости - это область видимости для идентификатора. Объем сам по себе не имеет ничего общего с временем жизни объекта. Когда что-то "оставляет сферу" в общем случае, что что-то не разрушается. Популярным заблуждением является использование формулировки "оставляет видимость" для обозначения точки уничтожения объекта.