Урок 88. Ссылки

   ⁄ 

 Обновлено 17 Окт 2017

  ⁄   

До этого момента мы успели рассмотреть два основных типа переменных:

  обычные переменные, которые хранят значения напрямую;

  указатели, которые хранят адрес другого значения (или null), и для доступа к которым выполняется операция разыменования указателя.

Ссылки — это третий базовый тип переменных. Ссылка — это тип переменной в C++, который работает как псевдоним другого объекта или значения.

C++ поддерживает три типа ссылок:

  ссылки на неконстантные значения (обычно их называют просто «ссылки» или «неконстантные ссылки»), которые мы обсудим в этом уроке.

  ссылки на константные значения (обычно их называют «константные ссылки»), которые мы обсудим в следующем уроке.

  в C++11 добавлены ссылки на r-value, о которых мы поговорим уже в следующих главах.

Ссылки на неконстантные значения

Ссылка (на неконстантное значение) объявляется с использованием амперсанда (&) между типом и именем ссылки:

В этом контексте амперсанд не означает «оператор адреса», он означает «ссылка на».

Ссылки как псевдонимы

Ссылки обычно ведут себя идентично значениям, на которые они ссылаются. В этом смысле ссылка работает как псевдоним объекта, на который она ссылается.

Например:

Результат:

9
10

В примере выше ref и value обрабатываются как одно целое.

Использование оператора адреса с ссылкой приведет к возврату адреса значения, на которое ссылается ссылка:

Краткий обзор l-value и r-value

В 10 уроке мы уже рассматривали, что такое l-value и r-value, и говорили вам тогда не слишком беспокоиться о них. Теперь же, наконец, мы дошли до того момента, где эти термины уже будет полезно не только вспомнить, но и использовать.

l-value — это объект, который имеет определенный адрес памяти (например, переменная x) и сохраняется за пределами одного выражения. r-value — это временное значение без определенного адреса памяти и с областью видимости выражения (т.е. сохраняется в пределах одного выражения). В качестве r-values могут быть как результаты выражения (например, 2 + 3), так и литералы.

Ссылки должны быть инициализированы

Ссылки должны быть инициализированы при создании:

В отличие от указателей, которые могут содержать нулевое значение, ссылки нулевыми быть не могут.

Ссылки на неконстантные значения могут быть инициализированы только неконстантными l-values. Они не могут быть инициализированы константными l-values или r-values.

Обратите внимание, во втором случае вы не можете инициализировать неконстантную ссылку константным объектом – иначе вы могли бы изменить значение константного объекта через ссылку, что уже является нарушением понятия «константа».

Ссылки не могут быть переприсвоены

После инициализации изменить объект, на который указывает ссылка, нельзя. Рассмотрим следующий фрагмент:

Обратите внимание, во втором стейтменте (5 строчка) выполняется не то, что вы могли бы ожидать! Вместо переприсваивания ref (ссылаться на переменную value2), значение из value2 присваивается переменной value1 (на которое и ссылается ref).

Ссылки в качестве параметров в функциях

Ссылки чаще всего используются в качестве параметров в функциях. В этом контексте ссылка-параметр работает как псевдоним аргумента, и сам аргумент не копируется при передаче в параметр. Это в свою очередь улучшает производительность, если аргумент слишком большой или затратный для копирования.

В 82 уроке мы говорили о том, что передача аргумента-указателя функции, позволяет функции при разыменовании этого указателя напрямую изменять значение аргумента.

Ссылки работают аналогично. Поскольку ссылка-параметр — это псевдоним аргумента, то функция, использующая ссылку-параметр, может изменять аргумент, переданный ей, также напрямую:

Результат:

7
8

Когда аргумент x передан в функцию, то параметр функции ref становится ссылкой на аргумент x. Это позволяет функции изменять значение x непосредственно через ref! Обратите внимание, переменная x не обязательно должна быть ссылкой.

Совет: Передавайте аргументы в функцию через неконстантные ссылки-параметры, если они должны быть изменены функцией в дальнейшем.

Основным недостатком использования неконстантных ссылок в качестве параметров в функции является то, что аргумент должен быть неконстантным l-value, т.е. константой или литералом он быть не может. Мы поговорим об этом подробнее (и то как это обойти) в следующем уроке.

Ссылки как более легкий способ доступа к данным

Второе (гораздо менее используемое) применение ссылок заключается в более легком способе доступа к вложенным данным. Рассмотрим следующую структуру:

Предположим, нам нужно работать с полем value1 структуры Something переменной other структуры Other (звучит сложно, но такое также встречается на практике). Обычно доступ к этому полю осуществлялся бы через
other.something.value1. А если есть много отдельных случаев доступа к этому члену? Код может стать несколько громоздким и беспорядочным. Ссылки же предоставляют более легкий способ доступа:

Таким образом, следующие два стейтмента идентичны:

Ссылки позволяют сделать ваш код более чистым и понятным.

Ссылки против указателей

Ссылки с указателями имеют интересное соотношение. Ссылка – это тот же указатель, который неявно разыменовывается при доступе к значению, на которое он указывает (под капотом ссылки реализованы компилятором с помощью указателей). Таким образом, в следующем:

*ptr и ref обрабатываться будут одинаково. Т.е. это одно и то же:

Поскольку ссылки должны быть инициализированы валидными объектами (они не могут быть нулевыми) и не могут быть изменены позже, то они, как правило, безопаснее указателей (так как риск разыменования нулевого указателя отпадает). Однако они немного ограничены в функциональности, по сравнению с указателями.

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

Итого

Ссылки позволяют определять псевдонимы для других объектов или значений. Ссылки на неконстантные значения могут быть инициализированы только неконстантными l-values. Они не могут быть переприсвоены после инициализации.

Ссылки чаще всего используются в качестве параметров в функциях, когда мы либо хотим изменить значение аргумента, либо хотим избежать его затратного копирования.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (4 оценок, среднее: 4,75 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *