Ссылки определяются как псевдонимы.Стандарт не определяет, как они представлены, хотя реализации не сильно различаются.По существу:
- В общем случае ссылка - это скрытый адрес объекта (например, указатель)
- Когда это возможно, компилятор будет стремиться исключитьindirection
Давайте посмотрим, как оно переводится, начиная с вашей программы:
int main()
{
int *pi = new int(50);
int &ri = *pi;
ri = 30;
std::cout << "val = " << ri << " , " << *pi << std::endl;
}
Мы можем исключить ri
, поскольку объект, с которым он связан, известенкомпилятором:
int main()
{
int *pi = new int(50);
*pi = 30;
std::cout << "val = " << *pi << " , " << *pi << std::endl;
}
Мы можем исключить *pi
, поскольку его окончательное значение известно компилятору:
int main() {
new int(50); // stupid possible side effect usually forbid to optimize this out
std::cout << "val = " << 30 << " , " << 30 << std::endl;
}
Я хотел бы отметить, что в вашем примере new
Вызов полностью бесполезен, вы также можете ссылаться на объекты, которые не были динамически распределены.
int main() {
int i = 50;
int& ri = i;
ri = 30;
std::cout << "val = " << ri << " < " << i << std::endl;
}
был одинаково действителен и без утечки памяти.
Возвращаясь к нашему различию междупредставления:
void swap(Foo& left, Foo& right);
обычно реализуются в виде:
void swap(Foo* left, Foo* right);
В этом случае ссылка в итоге занимает (некоторое) пространство (столько же, сколько указатель).
С другой стороны:
class Object {
public:
Object(): foo(f), f() {}
Foo const& foo;
void set(Foo const& value);
private:
Foo f;
};
Компилятор обычно не дает foo
представление времени выполнения.Тот факт, что это ссылка const
, будет использоваться для ограничения возможных методов, вызываемых на f
, теми, кто не изменяет его (семантическая разница), но во время выполнения они будут напрямую передаваться f
.