Комментарии 22
НЕ ИСПОЛЬЗУЙТЕ ССЫЛКИ и вы избежите почти всех проблем! (ц)
Ссылки и указатели это отличная тема для обсуждения дизайна языков программирования. Как лучше?
Указатели - это наиболее низкоуровневая абстрация, ближе всего к реальности и значит содержащая меньше всего противоречий. И еще указатели явные, их нужно разыменовывать каждый раз при использовании.
Ссылки - более высокоуровневая конструкция, также они кажутся более безопасными (хотя разумеется это не так - можно например сделать ссылку на разыменованный указатель, указывающий на память, которую затем освободить).
Если подумать то получаются как минимум следующие аспекты:
Явность/неявность при обращении (нужно или нет "разыменовывать")
Встроенная нуллабельность указателей и ненуллабельность ссылок
Возможность адресной арифметики
Адресная арифметика считается источником ошибок, хотя в низкоуровневом программировании от нее никуда не деться. Но это как раз решаемый вопрос, можно потреборвать чтобы она выполнялась только в каком нибудь "unsafe" контексте. В большинстве случаев указатели нужны лишь для динамически создаваемых объектов и там никакая арифметика не нужна.
Нуллабельность... она в языках программирования нужна, во многих случаях есть специальное состояние null, которое нужно выразить явно, а во многих других такого состояния нет. И хорошо если синтаксис языка предоставляет единый механизм для этого.
Остается явность/неявность - самое непростое, поскольку касается самой идеологии написания кода. Иногда важно явно выразить что происходит именно обращение по указателю; а иногда нам все равно, что там внутри - переменная просто представляет объект, а как он там хранится - без разницы.В Си (еще до C++) придумали операцию "стрелка" "->" специально для явного обращения к полям структуры по указателю, хотя ничто не мешало задействовать операцию "точка" - конфликта не было бы, в Си указатель не может быть одновременно составным объектом. Сделали так именно для явного обращения, такова идеология языка. В последующих языках от этого отказались, там везде "точка". В Go работают оба способа: (*myPointer).field и myPointer.field
спасибо это классика )
В 2025 году вроде уже можно обмазаться смарт поинтерами и не заморачиваться
И потом неожиданно обнаружить, что заметная доля времени уходит на апдейты счётчиков ссылок и прочие не имеющие отношения к целевой задаче вещи.
Но ведь это произойдёт только если сознательно выбрать смарт-поинтеры, реализующие модель совместного владения. Что, по идее, следует делать только если в совместном владении есть необходимость, и в таком случае оплата цены в виде счётчиков неизбежна.
Подумать о том, что даже если пойнтер сохраняется и используется в куче мест, владелец реально может быть один - это уже надо заморочиться )
Reference is just a const T* (но не всегда)
const T* это неизменяемость объекта, что конечно же для не-const ссылки неверно.
T* const = T&
const T* const = const T&
Из статьи так и не понял зачем ключевое слово ref в Rust, если есть &
В ветках match знак & является частью описания типа, по которому производится попытка сопоставления, a ref - не является, он говорит "сопоставь с таким-то типом, а потом дай мне на него ссылку вместо сожрать насовсем".
нужно для того чтобы возращать обьект типа наверно, в С++ так же можно протестить
template<typename T>
class Test{
public:
T a[3];
Test(){}
T& operator [](int idx) { return this->a[idx]; }
const T* data1() const { return &a[0]; }
T* data1() { return &a[0]; }
};
и например
Test test;
test.data1();
не тоже самое что test[0]
вообще изюминка в том что ссылка хранит только значение), а указатель и адрес и значение )
{
int a=1;
int *p = &a;
std::println("{} {}", p,*p);
}
таким образом граница контекста владения строго в { пока идет скобочка владеем через указатель к ресурсу } тут уже другая область, это как раз с чем типо-боролись, а это фишка ), это переплетается тесно с контекстным вызовом
тоесть просто в одном файле мы можем работать ток с указателями, если нужны и ресурсы и -O3 -ffast-math, и сложная контекстная логика, то нужен интерфейс и в том классе вся логика, тогда компилятор поймёт контекст и всё наладится такой тонкий нюанс так появился паттерн одиночка)
^ без этого в одном файле смешаются контексты и будет казаться что не правильная логика, но это на самом деле из-за контекста(владение ресурсом смешается с контекстом исполнения вызываемого класса например или тела цикла ) поэтому надо разграничить владение по контекстным вызовам, тоесть разграничения класс-интерфейс определяет контекст вот что я понял )
---
ну тоесть в С как раз доступен только указатель так что всё подпадает в логику )
---
например вызвать новый файл пронаследоваться от одиночки и в нём вызывать ресурсы, некие хендлеры ) тогда всё встаёт на свои места) и файл мейн тогда вызывает корректно контекст исполнения одиночки )
для меня это открытие )
"изюминка в том что ссылка хранит только значение"
Если мы говорим о C++ то это неверно, ссылка вообще не имеет никакой ячейки в памяти, поэтому ничего хранить не может, в данном случае вы помещаете в *p адрес a, & - операция взятия адреса, обратная разыменовыванию, не более того
Если мы говорим про Rust, то там ссылки это указатели с гарантией безопасности - всегда объект существует, пока существует ссылка, ссылка не может указывать вникуда или на объект не имеющий отношения к ссылке, никто это объект не тронет без твоего ведома, если у тебя владеющая ссылка и т.д.
Если мы говорим о C++ то это неверно, ссылка вообще не имеет никакой ячейки в памяти, поэтому ничего хранить не может,
А если взять и посмотреть в ассемблерный код
Давайте посмотрим, не вопрос, я уже смотрел, не выделяется никакая память под ссылки как минимум в варианте C++11, даже с move семантикой, просто берется адрес, в худшем варианте - косвенной адресацией и передается, физически ни в данных программы, ни в стеке, ни в куче ничего не видел чтобы выделялось
Если вы утверждаете обратное - приведите пример где C++ под ссылку выделяет память аналогично указателю, хоть один пример, почему я должен доказывать то, чего никогда не видел
ну вот борьба с указателями приведёт к тому в итоге что ими надо будет пользоваться и вы привели пример что в расте без них никак
а что ссылка хранит окей адрес в адресе значение.
а указатель и адрес показать может, и значение, и еще указатель может в арифметику указателей
Упустил я этот пример, если вам в Rust нужен именно сырой указатель, скорее всего вы делаете что-то не то, дайте пример, где он? Если умный указатель, то их там полно - Box, Rc, Arc, RefCell, Weak, на любой вкус и цвет, только это не указатель из Си, как и ссылка в Rust это не ссылка из С++
"указатель и адрес показать может, и значение, и еще указатель может в арифметику указателей"
И ещё в кучу багов, которые чтобы поймать можно потеть больше чем писал, например uaf, если вы откроете какой-нибудь крупный проект, например chromium вы обнаружите там за 1 месяц май 2025-го года тысячи уязвимостей use after free, некоторые из них написано "дают не авторизованному пользователю выполнить произвольный код на целевой платформе'
Ссылки и указатели в C++