Сообщение от
kin4stat
Разыменование указателя дает lvalue ссылку на тип под указателем.
Фактически работает примерно так: звездочка около типа заменяется амперсандом(ссылкой)
, где T - произвольный тип
Не, что-то не так. Поправьте, если неправильно понял.
Унарный оператор
* над
указателем на T это
T (lvalue).
Ссылка на T (т.е.
T&) может быть инициализирована объектом типа
T (не
T&).
Так как любое lvalue явно идентифицируется в памяти, обращение к ссылке под капотом будет ссылаться к адресу, в котором расположен этот lvalue
Сообщение от
voodushevlen
В языке C и C++ существуют указатели
Вам уже много написали всего, поэтому попробую немного вокруг описать, может это поможет
Ссылочный тип данных - это новояз именно C++. Сохраняя общую семантику указателей (в частности, техническую часть), он становится более безопасным и предпочитаемым типом нежели указатель, так как:
- Ссылка не может быть неопределенной/нулевой/указывать на невалидный объект. Представьте, как C++ обошел все языки, в которых только недавно решили null-safety вводить;
- Ссылка четко определена как немутабельная в отличии от указателя (нельзя поменять куда она ссылается). Кроме того, не бывает ссылки на ссылку, массив ссылок и прочих головоломок;
- Ссылка исходя из правил и ограничений выше указанных имеет определенное поведение, из разряда, что ссылки должны быть инициализированы для членов класса, что константная ссылка продлевает срок жизни объекта и так далее.
- Удобство использования, так как не нужно постоянно разыменовывать его и прочие мелочи.
Надеюсь не будет звучать тупо, но в целом при использовании ссылок не нужно беспокоится об адресах, ссылки - это о значениях, которые расположены по адресам, указатели - наоборот, об адресах, которые указывают на значения.
Окей, предположим, что мы хотим пользоваться этой вашей крутой ссылкой хваленой, но нужно это для адреса 0xBAB230:
C++:
Код:
// ** давайте не будет придираться к тому, что не всегда sizeof(int) == sizeof(int*)
// да и вообще адрес памяти - не совсем верный термин, так как это не всегда линейное пространство, c/c++ - это не только x86/arm
// сохраним желаемый адрес памяти в переменной. Уже выше говорили, что 0xBAB230 - числовой литерал, значит и тип переменной int
int
address_as_int
=
0xBAB230
;
// так как у нас адрес, то объявить ссылку мы не можем, нужно получить значение по этому адресу, для чего будем пользоваться указателями
// чтобы представить число как адрес в памяти, его необходимо преобразовать в указатель
int
*
address_as_pointer
=
(
int
*
)
address_as_int
;
// здесь есть 3 варианта
// *address_as_pointer -> разыменование указателя. Получит то, куда он ссылается. Т.е. значение по адресу 0xBAB230
// address_as_pointer -> адрес, куда указывает указатель, т.е. 0xBAB230
// &address_as_pointer -> адрес самого указателя address_as_pointer, это такая же переменная как и все другие,
// просто содержит в себе адрес, а значит должна где-то находиться в памяти
// как уже подчеркнули, чтобы инициализировать ссылку, нужно передать ей значение, т.е. разыменовать указатель
// если указатель неверный, то "ошибка" случится на этапе разыменовывания указателя, но не инициализации ссылки
int
&
reference
=
*
address_as_pointer
;
// теперь можно пользоваться, "разыменовывание" ссылки сделает сам компилятор,
// причем с гарантией того, что он указывает на инициализированный объект
// reference = 0;
// а вот с указателем проблемы, ведь нет гарантии, что address_as_pointer указывает на валидный адрес (даже если бы сделали его константным),
// до момента его разыменовывания это может быть бомба замедленного действия.
// Каждое разыменовывание выполняется самостоятельно со всеми рисками
// *address_as_pointer = 0;