Справочник (C ++) - Reference (C++)

в C ++ язык программирования, а ссылка это простой ссылка тип данных, который менее мощный, но более безопасный, чем тип указатель тип унаследованный от C. Название Справочник по C ++ может вызвать путаницу, поскольку в информатике ссылка - это общий концептуальный тип данных, указатели и Ссылки на C ++ являются конкретными реализациями ссылочного типа данных. Определение ссылки в C ++ таково, что она не должна существовать. Его можно реализовать как новое имя для существующего объекта (аналогично ключевому слову rename в Ada).

Синтаксис и терминология

Объявление формы:

<Type>& <Name>

куда <Type> это тип и <Name> является идентификатор чей тип ссылка на <Type>.

Примеры:

int а = 5;int& r_a = а;внешний int& r_b;

Здесь, r_a и r_b относятся к типу "ссылка на int"

int& Фу();

Фу это функция, которая возвращает "ссылку на int"

пустота Бар(int& r_p);

Бар - это функция со ссылочным параметром, который является "ссылкой на int"

учебный класс Мой класс { int& m_b; /* ... */ };

Мой класс это учебный класс с членом, который ссылается на int

int FuncX() { возвращаться 42 ; };int (&f_func)() = FuncX;

FuncX это функция, которая возвращает (не ссылочный тип) int и f_func является псевдоним за FuncX

const int& ссылка = 65;

const int & ref постоянная ссылка, указывающая на часть хранилища, имеющую значение 65.

Типы, которые являются своего рода "ссылкой на <Type>"иногда называют ссылочные типы. Идентификаторы ссылочного типа называются ссылочные переменные. Позвонить им Переменнаяоднако, как мы увидим, на самом деле это неправильное название.

Связь с указателями

Ссылки C ++ отличаются от указателей несколькими существенными способами:

  • Невозможно напрямую ссылаться на объект ссылки после того, как он определен; любое вхождение его имени относится непосредственно к объекту, на который он ссылается.
  • После того, как ссылка создана, ее нельзя впоследствии использовать для ссылки на другой объект; Не может быть пересаженный. Часто это делается с помощью указателей.
  • Ссылки не могут быть ноль, тогда как указатели могут; каждая ссылка относится к какому-либо объекту, хотя она может быть или недействительной. Обратите внимание, что по этой причине контейнеры ссылок не разрешены.
  • Ссылки не могут быть неинициализированными. Поскольку повторно инициализировать ссылку невозможно, они должны быть инициализированы сразу после создания. В частности, локальные и глобальные переменные должны быть инициализированы там, где они определены, а ссылки, которые являются членами данных экземпляров класса, должны быть инициализированы в списке инициализаторов конструктора класса. Например:
    int& k; // компилятор пожалуется: ошибка: `k 'объявлен как ссылка, но не инициализирован

Существует простое преобразование между указателями и ссылками: оператор адресации (&) даст указатель, ссылающийся на один и тот же объект при применении к ссылке, и ссылку, которая инициализируется из разыменования (*) значения указателя будет ссылаться на тот же объект, что и этот указатель, где это возможно без вызова неопределенного поведения. Эта эквивалентность является отражением типичной реализации, которая эффективно компилирует ссылки в указатели, которые неявно разыменовываются при каждом использовании. Хотя это обычно так, стандарт C ++ не заставляет компиляторы реализовывать ссылки с помощью указателей.

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

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

  • Если он относится к объекту с автоматическим выделением, который выходит за рамки,
  • Если он относится к объекту внутри блока динамической памяти, который был освобожден.

Первый легко обнаружить автоматически, если ссылка имеет статическую область видимости, но все же проблема, если ссылка является членом динамически выделяемого объекта; второй обнаружить сложнее. Это единственные проблемы со ссылками, которые соответствующим образом решаются разумной политикой распределения.

Использование ссылок

  • Помимо полезной замены указателей, одно удобное применение ссылок - это списки параметров функций, где они позволяют передавать параметры, используемые для вывода, без явного взятия адреса вызывающей стороной. Например:
пустота Квадрат(int Икс, int& out_result) {  out_result = Икс * Икс;}

Тогда следующий вызов поместит 9 в у:

int у;Квадрат(3, у);

Однако следующий вызов приведет к ошибке компилятора, поскольку ссылочные параметры не определены с const может быть привязан только к адресуемым значениям:

Квадрат(3, 6);
  • Возврат ссылки позволяет назначать вызовы функций:
    int& Preinc(int& Икс) {  возвращаться ++Икс;  // "return x ++;" было бы неправильно}Preinc(у) = 5;  // то же, что ++ y, y = 5
  • Во многих реализациях обычные механизмы передачи параметров часто подразумевают дорогостоящую операцию копирования для больших параметров. Ссылки квалифицированы с const - полезный способ передачи больших объектов между функциями, позволяющий избежать этих накладных расходов:
    пустота FSlow(BigObject Икс) { /* ... */ }  пустота FFast(const BigObject& Икс) { /* ... */ }BigObject у;FSlow(у);  // Медленно, копирует y в параметр x.FFast(у);  // Быстро, дает прямой доступ только для чтения к y.

Если FFast на самом деле требуется собственная копия Икс что он может изменять, он должен явно создавать копию. Хотя тот же метод может быть применен с использованием указателей, это потребует изменения каждого сайта вызова функции, чтобы добавить громоздкий адрес-of (&) к аргументу, и было бы так же сложно отменить, если бы объект впоследствии стал меньше.

Полиморфное поведение

Продолжая взаимосвязь между ссылками и указателями (в контексте C ++), первые демонстрируют полиморфные возможности, как и следовало ожидать:

#включают <iostream>учебный класс А { общественный:  А() = дефолт;  виртуальный пустота Распечатать() { стандартное::cout << "Это класс А п"; }};учебный класс B : общественный А { общественный:  B() = дефолт;  виртуальный пустота Распечатать() { стандартное::cout << "Это класс B п"; }};int главный() {  А а;  А& ref_to_a = а;  B б;  А& ref_to_b = б;  ref_to_a.Распечатать();  ref_to_b.Распечатать();}

Приведенный выше источник является действительным C ++ и генерирует следующий вывод:
Это класс А

Это класс B

Определение ISO

Ссылки определены стандартом ISO C ++ следующим образом (за исключением раздела примеров):

В объявлении T D, где D имеет вид

& D1

а тип идентификатора в объявлении T D1 - "производный-декларатор-тип-список Т, "тогда тип идентификатора D -"производный-декларатор-тип-список ссылка на Т. "Ссылки с квалификацией cv имеют неправильный формат, кроме случаев, когда квалификаторы cv (const и летучий) вводятся с помощью typedef (7.1.3) или аргумента типа шаблона (14.3), и в этом случае cv-квалификаторы игнорируются. [Пример: в

typedef int& А;const А ареф = 3;  // плохо сформированный;// неконстантная ссылка, инициализированная с помощью rvalue

тип ареф "ссылка на int", нет "const ссылка на int". ] [Примечание: ссылку можно рассматривать как имя объекта. ] Декларатор, указывающий тип "ссылка на резюме void "неправильно сформирован.

Не указано, требует ли ссылка хранилища (3.7).

Не должно быть ссылок на ссылки, массивов ссылок и указателей на ссылки. Объявление ссылки должно содержать инициализатор (8.5.3) кроме случаев, когда объявление содержит явное внешний спецификатор (7.1.1), является объявлением члена класса (9.2) в объявлении класса или является объявлением параметра или возвращаемого типа (8.3.5); см. 3.1. Ссылка должна быть инициализирована для ссылки на действительный объект или функцию. [Примечание: в частности, пустая ссылка не может существовать в четко определенной программе, потому что единственный способ создать такую ​​ссылку - это привязать ее к «объекту», полученному разыменованием нулевого указателя, что вызывает неопределенное поведение. Как описано в 9.6, ссылку нельзя напрямую привязать к битовому полю. ]

— ISO / IEC 14882: 1998 (E), стандарт ISO C ++, в разделе 8.3.2 [dcl.ref]

внешняя ссылка

Рекомендации