Ссылка (C++)

Ссылка (C++)

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

Содержание

Введение

Если мы объявили переменную без спецификатора extern, то для хранения значений выделяется память. Чтобы изменить или прочитать значение переменной (то есть значение находящейся в этой области памяти), мы обращаемся по имени этой переменной. В языке C имя сущности (переменной, типа, функции и т.д.) — это идентификатор. С точки зрения программиста, объявляя ссылку (или же указывая, что она будет возвращаемым значением или аргументом функции), мы задаём альтернативный идентификатор для уже созданного объекта. В языке C ссылок нет. С точки зрения реализации, ссылка — это, по сути, указатель, который жестко привязан к области памяти, на которую он указывает, и который автоматически разыменовывается, когда мы обращаемся по имени ссылки (это легко проверить, дизассемблируя простой пример).

Например:

        /* конкретные адреса переменных могут быть другими */
        int a;       //переменная с именем "a" типа int размещена по адресу 0xbfd86d6c
        int &ra = a; //задано альтернативное имя (ra) для переменной по адресу 0xbfd86d6c
 
        /* символ "&" используемый для уже созданного объекта является операцией взятия адреса *
         * (и эта операция не есть ссылка), то есть &a тут означает получить адрес переменной  *
         * к которому привязано имя "a"                                                        */
        cout << &a << '\n' << &ra << '\n';

В stdout будет записано:

0xbfd86d6c
0xbfd86d6c

То есть оба имени "a" и "ra" привязаны к одному и тому же адресу.

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

Важно отличать ссылки от оператора взятия адреса & (address of). Оператор взятия адреса используется для уже созданного объекта с целью получить его адрес (то есть адрес области памяти, где хранятся значения), а ссылка это только задание альтернативного имени объекта (с точки зрения программиста, а не реализации). Например:

        int a;       //переменная типа int размещена по адресу 0xbfd86d6c с именем "a"
        int b = 3;
 
        /* создан указатель с именем "p" по адресу 0xbf971c4c, значение этого указателя *
         * адрес объекта с именем "a" - 0xbfd86d6c (это значение можно будет менять)    */
        int *p = &a;
 
        p = &b;      //присваиваем указателю новое значение соответствующее адресу переменной "b"

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

        int a = 3;
        int *p = &a; //объявили, создали, и инициализировали объект
 
        // здесь к уже созданному объекту с именем "p" применяется оператор "*", который означает
        // считать значение из "p", которое является адресом и далее считать данные по этому адресу
        cout << *p << '\n';

В stdout будет записано:

3

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

Объявление вида:

<Type> & <Name>

где <Type>тип и <Name>идентификатор, указывает идентификатор, чьим типом является ссылка на <Type>.

Примеры:

  1. int A = 5;
  2. int& rA = A;
  3. extern int& rB;
  4. int& foo ();
  5. void bar (int& rP);
  6. class MyClass { int& m_b; /* ... */ };
  7. int funcX() { return 42 ; }; int (&xFunc)() = funcX;

Здесь, rA и rB являются типами «ссылок на int», foo() — функция, возвращающая ссылку на int, bar() — функция с ссылкой в качестве параметра, которая ссылается на int, MyClass — класс (class) с членом, ссылающимся на int, funcX() — функция, возвращающая int, xFunc() — псевдоним для funcX.

Типы, относящиеся к «ссылка на <Type>», иногда называются ссылочными типами. Идентификаторы ссылочного типа называются ссылочными переменными. Называть их переменными в строгом смысле будет неправильно (показано дальше).

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

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

  • Невозможно ссылаться напрямую на объект ссылочного типа после его определения; каждое упоминание его имени напрямую представляет объект, на который он ссылается.
  • В качестве результата первого указания не могут быть выполнены никакие арифметические вычисления, приведения типов, взятия адреса и т.п.
  • После создания ссылки ее нельзя перевести на другой объект; в таких случаях говорят, не может быть переопределена. Это часто делают с указателями.
  • Ссылки не могут быть null (т.е.указывать в никуда), тогда как указатели - могут; каждая ссылка ссылается на некий объект, вне зависимости от его корректности.
  • Ссылки не могут быть неинициализированными. Так как невозможно переинициализировать ссылку, она должна быть инициализирована сразу после создания. В частности, локальные и глобальные переменные должны быть проинициализированы там же, где они определены, а ссылки, которые являются данными-членами сущностей класса, должны быть инициализированы в списке инициализатора конструктора класса.

Пример:


int& k; // компилятор выдаст сообщение: ошибка: 'k' declared as reference but not initialized ('k' объявлена как ссылка, но не инициализирована)


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

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

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

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

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

Применение ссылок

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

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

square(3, y);

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

square(3, 6);
  • Возврат ссылки также позволяет непредусмотренный синтаксис, в котором вызовы функции могут быть присвоены:
int& preinc(int& x) { ++x; return x; }
preinc(y) = 5; // то же, что и ++y, y = 5
  • Во многих реализациях, обычные механизмы передачи параметров часто подразумевают весьма затратную операцию копирования больших параметров. Ссылки, помеченные const, полезны в качестве способа передачи больших объектов между функциями без накладных расходов:
void f_slow(BigObject x) { /* ... */ }  
void f_fast(const BigObject& x) { /* ... */ }
BigObject y;
f_slow(y); // медленно, копирует y в параметр x
f_fast(y); // быстро, дает прямой доступ к y (только для чтения)
_

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

  • Причиной введения ссылок в язык С++ в основном являлась необходимость перегрузки операторов, применяемых к объектам пользовательских типов (классов). Как упоминалось выше, передача по значению громоздких объектов в качестве операндов вызывала бы лишние затраты на их копирование. С другой стороны, передача операндов по адресу с использованием указателей, приводит к необходимости взятия адресов операндов в выражениях. Например:
class BigClass
{
//...
  friend BigClass operator-(BigClass* left, BigClass* right);
//...
};
 
BigClass x, y, z;
//...
x = &y - &z;

Однако, выражение &y - &z уже имело определённый смысл в языке С.

Цитаты

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

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

а типом идентификатора в объявлении T D1 является производный тип ("derived-declarator-type-list) T,” тогда типом идентификатора D будет производная (“derived-declarator-type-list) ссылка на T.” Cv-ссылки являются плохо согласованными, исключая ситуацию, когда cv-квалификаторы (от англ. const ("константный") и volatile ("временный")) представлены через использование typedef (7.1.3) или шаблон аргумента типа (14.3), в случае чего игнорируются cv-квалификаторы. [Пример: в коде

typedef int& A;
const A aref = 3; // плохо согласовано;
// неконстантная ссылка инициализируется rvalue

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

Это не определяет, требуется ли ссылке выделение памяти (3.7).

Не должно быть ссылок на ссылки, массивов ссылок, а также указателей на ссылки. Объявление ссылки должно содержать инициализатор (8.5.3), за исключением случая, когда объявление содержит явный указатель extern (7.1.1) - объявление члена класса (9.2) внутри объявления класса, объявление параметра или возврат типа (8.3.5); смотри 3.1. Ссылка должна при инициализации ссылаться на корректный объект или функцию. [Примечание: точнее говоря, ссылка на null не может существовать в корректно написанной программе, так как единственным способом создать подобную ссылку является связывание ее с "объектом", полученном при помощи разыменования нуль-указателя, что вызывает неопределенное поведение. Как описано в 9.6, ссылка не может ограничиваться напрямую битовым полем. ] | cite = ISO/IEC 14882:1998(E), стандарт ISO C++, раздел 8.3.2 [dcl.ref]

См. также

Ссылки в программировании

Дополнительные источники


Wikimedia Foundation. 2010.

Игры ⚽ Нужно решить контрольную?

Полезное


Смотреть что такое "Ссылка (C++)" в других словарях:

  • ссылка — 1. ССЫЛКА, и; мн. род. лок, дат. лкам; ж. 1. к Сослать ссылать. Приговорить к ссылке в Сибирь. Это преступление каралось ссылкой на каторжные работы. 2. Пребывание на поселении в качестве ссыльного; время такого пребывания. Отбывать ссылку. Место …   Энциклопедический словарь

  • ссылка — См. доказательство делать ссылку... Словарь русских синонимов и сходных по смыслу выражений. под. ред. Н. Абрамова, М.: Русские словари, 1999. ссылка замечание, примечание, справка, упоминание, сноска; высылка, депортация; доказательство;… …   Словарь синонимов

  • Ссылка — словесное или цифровое указание внутри издания, адресующее читателя к другому изданию (библиогр. ссылка); к фрагменту текста, где содержатся дополняющие, расширяющие или поясняющие сведения о предмете речи в данном текстовом фрагменте; к… …   Издательский словарь-справочник

  • ССЫЛКА — вид уголовного наказания, состоит в удалении осужденного из места его жительства с обязательным поселением в определенной местности. В России применялись по суду или в административном порядке (см. Административная ссылка), главным образом в… …   Юридический словарь

  • ССЫЛКА — вид уголовного наказания удаление осужденного из места его жительства с обязательным поселением в определенной местности. В России применялись по суду или в административном порядке (см. Административная ссылка), главным образом в отношении лиц,… …   Большой Энциклопедический словарь

  • ССЫЛКА — ССЫЛКА, вид уголовного наказания удаление осуждённого из места его жительства с обязательным поселением в определённой местности. В России сложилась в 16 17 вв., наибольшее распространение получила в 19 нач. 20 вв., применялась по суду или в… …   Русская история

  • Ссылка — вид уголовного наказания удаление осужденного из места его жительства с обязательным поселением в определенной местности. В России применялись по суду или в административном порядке (см. Административная ссылка), главным образом в отношении лиц,… …   Политология. Словарь.

  • ССЫЛКА — вид уголовного наказания, состоящий в удалении осужденного из места его жительства с обязательным поселением в определенной местности. В России С. применялись по решению суда или в административном порядке (АДМИНИСТРАТИВНАЯ ССЫЛКА), главным… …   Юридическая энциклопедия

  • ССЫЛКА — 1. ССЫЛКА1, ссылки, жен. 1. только ед. Действие по гл. сослать ссылать. Царское правительство широко применяло ссылку революционеров в Сибирь. 2. Состояние, как результат этого действия. Приговорить к ссылке. Жить в ссылке. Сослать в ссылку.… …   Толковый словарь Ушакова

  • ССЫЛКА — 1. ССЫЛКА1, ссылки, жен. 1. только ед. Действие по гл. сослать ссылать. Царское правительство широко применяло ссылку революционеров в Сибирь. 2. Состояние, как результат этого действия. Приговорить к ссылке. Жить в ссылке. Сослать в ссылку.… …   Толковый словарь Ушакова

  • ссылка — ССЫЛКА, и, жен. 1. см. сослать. 2. Пребывание ссыльного на поселении, а также время такого пребывания. Жить в ссылке. II. ССЫЛКА, и, жен. 1. см. сослаться. 2. Выдержка из текста или указание источника, на к рый ссылаются. С. на первоисточник. С.… …   Толковый словарь Ожегова


Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»