Dyzzet|
C++ Data Science Алгоритмы Темы · Блог · YouTube
Указатели и ссылки в языке C++
А также Java и C♯

В языке C++ практически с самого начала его существования есть две реализации ссылочного типа: это указатели (pointers) и ссылки (references). Указатели достались от языка C. Ссылки не заменили указатели во всём, а умные/интеллектуальные указатели (smart pointers) не всегда стоит использовать вместо «сырых» (raw pointers). В C++11 появился новый тип — rvalue-ссылки — который преследует совсем иные цели.

Ссылки появились в C++ ещё в тот момент, когда он миновал этап C with Classes, для перегрузки операторов:

Страуструп Б. «Дизайн и эволюция C++», оригинал 1994 года

«Дуг Макилрой вспоминает, что однажды я объяснял ему некоторые проблемы, касавшиеся схемы перегрузки операторов. Он употребил слово „ссылка“, после чего я, пробормотав „спасибо“, выбежал из его кабинета, чтобы на следующий день появиться с практически готовым решением, которое и вошло в язык. Просто Дуг тогда напомнил мне об Algol68».

В первом приближении разница между указателями и ссылками такова (для сравнения — ссылки в языках Java и C♯).

 
Указатели в C
Указатели в C++
Ссылки в C++
Ссылки в языках Java и C♯
Обязательно инициализировать
–
–
+
–
Можно переназначить
+ (если не const)
+ (если не const)
–
+
Значение по умолчанию
Мусорное
Мусорное
–
null
Невалидное значение
NULL
NULL/nullptr (C++11)
–
null
Коллекции
+
+
–
+
Арифметика
+
+
–
–
Косвенность
+
+
–
–

Из таблицы видно, что ссылки в Java и C♯, несмотря на название, больше похожи на указатели в C и C++ (но без присущей им арифметики и косвенности — как указатели на указатели).

Указатели и ссылки различаются по константности. Ссылки больше всего напоминают в этом отношении указатели, которые нельзя изменять.

 
Может изменяться
Не может изменяться
Может изменять то, на что указывает
T* ptr
T* const ptr,
T& ref
Не может изменять то, на что указывает
const T * ptr ≡ T const * ptr
const T * const ptr,
const T& ref ≡ T const& ref

По указателю в C++ принято передавать объекты в низкоуровневые API или в такие функции, аргумент которых может равняться nullptr; их используют для внутренней организации структур данных. По ссылкам принято передавать объекты во всех остальных случаях, когда нужно избежать копирования или изменить объект внутри функции.

Бьерн Страуструп, создатель языка C++:

Бьянкуцци Ф., Уорден Ш. Пионеры программирования. Диалоги с создателями наиболее популярных языков программирования, 2011

Оригинал: Federico Biancuzzi, Shane Warden. Masterminds of Programming. Conversations with the Creators of Major Programming Languages, 2009

«В языке Java есть указатели. На самом деле там почти всё неявно оказывается указателем. Просто там их называют ссылками (references). В том, что указатели неявные, есть свои преимущества и недостатки. Попутно отмечу, что наличие подлинно локальных объектов (как в C++) также имеет как преимущества, так и недостатки. [...] А вездесущие неявно используемые в языке Java указатели (они же ссылки) закрывают путь ко всем этим возможностям [...]

Благодаря повсеместному и неявному использованию ссылок в Java, возможно, удалось упростить модель программирования и сборку мусора, но расход памяти при этом резко вырос — и соответственно выросли стоимость доступа к памяти (осуществляемого более косвенным образом) и расходы на выделение памяти.

Чего в языке Java, к счастью, нет, так это допускаемого языками C и C++ неправильного применения арифметики указателей. Но и эта проблема решается, если корректно писать код на языке C++, используя такие высокоуровневые абстракции, как потоки ввода/вывода, контейнеры и алгоритмы, а не занимаясь вознёй с указателями. [...]

Есть, однако, важная область, где указатели и действия с ними оказываются большим подспорьем: прямое и эффективное описание структур данных. Ссылок Java здесь оказывается недостаточно: например, с их помощью не опишешь операцию swap. Другой пример — простота непосредственного доступа к реальной памяти с помощью указателей: в любой системе должен быть язык, который может это сделать, и часто им оказывается C++.

„Отрицательная“ сторона наличия указателей (и массивов в стиле C) — это, конечно, возможность злоупотреблений: переполнение буфера, указатели на удалённую память, неинициализированные указатели и т. п. Но если корректно писать код на языке C++, всё не столь страшно. [...] Те, кто привык работать на C или придерживается старого стиля в языке C++, с трудом верят тому, что управление ресурсами на основе областей видимости представляет собой исключительно мощный инструмент».

14 июня 2022
C++
Зарегистрируйтесь и войдите, чтобы оставлять комментарии и голосовать.

Также может быть интересным
© MMXI—MMXXIII. RSS. Поддержать сайт
Светлая тема / тёмная тема