Ссылки С++

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Есть такая тема, решил освежевать в памяти подзабытый прекрасный С++, пошёл читать учебник и наткнулся на главу "ссылки", где расписывают, как прекрасно, что вызываемая функция может менять переменные вызывающей функции по ссылке. Внутренне содрогнулся. Это действительно прекрасно, или это уже забытая фича С++, или я просто уже не секу?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

не секете. Ссылки это еще широко используемый инструмент Си, как бы не хуже указателей.  Как вам такая штука func()=5; 

#190

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

Ссылки это еще широко используемый инструмент Си

Одна только беда - нету в Си никаких ссылок.

А 

qwone пишет:
такая штука func()=5;
Вполне, кстати, реализуется и на указателях.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78, можно конкретизировать вопрос?

Вас интересует наше мнение о ссылках и их полезности? Или что в них такого, чего нельзя было сделать указателями и для чего их ввели? Или какого ответа Вы ждёте?

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Именно. Я сишник, и соответственно думаю указателями. Мой вопрос в том: зачем нужны ссылки? Прототип объявляется со ссылками, а я то передаю аргументы без ссылок (как я думаю - по значению), может я прототип не видел, или забыл как он выглядит. В чём сила ссылок? Или лучше ими вообще не зооупотреблять?

Schwarz78
Offline
Зарегистрирован: 19.01.2019

И, конечно, именно ваше мнение, ЕвгенийП.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Указатели я тож люблю, на функции меньше, но где здесь ссылки?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Schwarz78 пишет:

Указатели я тож люблю, на функции меньше, но где здесь ссылки?

Дать ??

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Извините, Пух. Да. Ссылка. Можете объяснить, почему она необходима в здесь? А главное - что она делает? Красиво написано - не всегда красиво реализовано. Но чаще именно так. Объясните мне?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Самое сложное в ссылке это понять что такое ссылка , а что ссылкой не является. Сама по себе ссылка бонуса не приносит. Фишка в том что она имеет силу в функциях, как возврат по ссылке, так и параметры внутри ссылки. И самое главное экономит память. То есть по факту использует объекты которые есть, а не делает дубликаты внутри функций.  Указатели вроде тоже, но они жрут память на адресс указателя.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, «нужны» – понятие относительно, всё можно сделать и без них (как и без почти всего остального – на машине Тьюринга) вопрос в удобстве. В целом ссылка – это более высокоуровневый объект (гораздо дальше от железа), чем указатель.

Будучи один раз проинициализирована, она может быть использована вместо самого объекта, на который ссылается, как другой способ добраться до него. Если не говорить о несколько экзотических rvalue ссылках, то ссылка – lvalue, т.е. её можно использовать слева от операции присваивания. Любая операция с переменной-ссылкой (кроме её инициализации) – на самом деле операция с объектом, на который она ссылается. С нею самой нельзя сделать ничего. Например, если переменная-ссылка стоит в левой части присваивания, то значение будет присвоено объекту, на который она ссылается (а вовсе не ей самой).

Ссылка не может не быть инициализирована. Во время выполнения ссылка всегда ссылается на существующий объект правильного типа и т.д. (в отличие от указателя, который может указывать куда угодно и на что угодно). Всегда означает «всегда». Не бывает null-ссылки, например. Это сильно повышает безопасность работы с полученными функцией аргументами. Указатель ведь может быть nullptr, и это ещё полбеды, а может вообще, куда попало смотреть

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

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

У ссылок есть механизм «схлопывания» (collapsing). Немного упрощая это означает, что если, например, в typedef Вы определите новый тип NT через тип Т, а потом попытаетесь сделать ссылку на NT – в реальности получится ссылка на T.

Я говорил только о т.н. lvalue ссылках. Бывают ещё и rvalue ссылки, но разговор о них уведёт нас далеко – они придуманы для очень специфических вещей типа «семантики перемещения», давайте не будем.

Для чего же их вводили?

Ну, о безопасности (по сравнению с указателями) мы уже говорили.

Кроме того, в С++ (в отличие от С) существуют объекты у которых могут быть конструкторы, деструкторы, перегруженные операторы (никто не мешает написать собственный + или – или преобразование к какому-нибудь типу, взятие индекса и т.п.). Доступ к объекту по указателю иногда создаёт проблемы для отработки всех этих вещей (особенно если используется утиная типизация), доступ же по ссылке проблем не создаёт, т.к. операция над ссылкой – суть операция над самим объектом и, стало быть, все его механизмы отработают штатно.

Ну, вот, не знаю, сумбурно как-то получилось.

P.S.
И да, часто приходится читать - что ссылка - это адрес, так вот НЕТ. Категорически нет. Это не адрес (хотя dynehtyyt jyf может быть реальзована череp адрес, но это внутрення кухня). Но семантически это НЕ адрес. Тут нет адресной арифметики, нет "массивности" и т.п. - ссылка, это "ссылка на объект, которую можно использовать везде, где можно использовать объект" и не более того. Это боле высокий уровень абстракции, чем адрес. Будь она адресом, кто бы ей мешал иметь собственный адрес и адресную арифметику? Или из вредности убрали? Просто семантически ссылка адресом не является.

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

Schwarz78
Offline
Зарегистрирован: 19.01.2019

ЕвгенийП, это как вы ссылку воспринимаете. Мне до такой формализации ещё ехать и ехать. Хотя я уже понял, что лучше не трогать то, что не понял. Да и медведь, вроде по-русски пишет, а тоже хрен поймёшь. Единственный выход - пытаться кодить и смотреть ассембелер, как в децве)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78 пишет:

Единственный выход - пытаться кодить и смотреть ассембелер, как в децве)

Не выйдет, почитайте мой последний абзац. Может и так и эдак вылезти :)

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Это да, компиляторы очень умные стали. То, что умнее меня, я понял 20 лет назад, и перешёл на С. Теперь вот о более умных компиляторах задумался. Но вижу, что рано вопросы задаю. Надо самому покодить для начала.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

"Ну, о безопасности (по сравнению с указателями) мы уже говорили."

Разве? Когда и где? Меня этот аспект вообще интересует, а в плане ссылок - особенно, уж очень они опасные на первый взгляд.

sadman41
Offline
Зарегистрирован: 19.10.2016

Ссылка - это вот так func(type something&) или речь о чём-то другом?  

Schwarz78
Offline
Зарегистрирован: 19.01.2019

В общем, "пока мне это не понадобилось, я не стану об этом думать". А когда понадобится - я сам пойму зачем это нужно.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Да, int foo( int& x, int& y ), и вызываем if( foo( x, y ) ) {}. А х и y - мои переменные. А foo может их легко поменять.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

"Кроме того, в С++ (в отличие от С) существуют объекты у которых могут быть конструкторы, деструкторы, перегруженные операторы (никто не мешает написать собственный + или – или преобразование к какому-нибудь типу, взятие индекса и т.п.). Доступ к объекту по указателю иногда создаёт проблемы для отработки всех этих вещей (особенно если используется утиная типизация), доступ же по ссылке проблем не создаёт, т.к. операция над ссылкой – суть операция над самим объектом и, стало быть, все его механизмы отработают штатно."

Вот, уже начало укладываться в голове зачем оно нужно, спасибо.

sadman41
Offline
Зарегистрирован: 19.10.2016

Меня смущает то, что компилятор может сам по-себе заменить ссылку значением. Не бывает такого, что внутри функции *param = 10 (условно) не сработает и из функции ничего не вернется? 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
Schwarz78
Offline
Зарегистрирован: 19.01.2019

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78 пишет:

"Ну, о безопасности (по сравнению с указателями) мы уже говорили."

Разве? Когда и где? 

ЕвгенийП пишет:
Во время выполнения ссылка всегда ссылается на существующий объект правильного типа и т.д. (в отличие от указателя, который может указывать куда угодно и на что угодно). Всегда означает «всегда». Не бывает null-ссылки, например. Это сильно повышает безопасность работы с полученными функцией аргументами. Указатель ведь может быть nullptr, и это ещё полбеды, а может вообще, куда попало смотреть

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Извините, Пух, но смотреть видео - это слишком долго, а жизнь и так мимолётна. Лучше читать книги.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Да, точно. Я может быть тогда стану совсем наглым, и попрошу небольшой скетч, где ссылка будет категорически востребована. Если такое возможно.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

лучше один раз увидеть, чем 100 раз прочитать и потом еще и не понять прочитаное.Если бы поняли что прочитали, то и этой темы не было.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Так я и спросил, потому что не понял. Вы уверены, что все понимают всё про ссылки? Я точно знаю, что личный опыт гораздо круче чужого, но чужой опыт - ещё круче, когда осознанный.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:

Меня смущает то, что компилятор может сам по-себе заменить ссылку значением. Не бывает такого, что внутри функции *param = 10 (условно) не сработает и из функции ничего не вернется? 

Нет, не может. Алгоритмы обнаружения побочных эффектов давно известны и в этом ошибок не бывает. Если есть такая конструкция,  то он не будет заменять ссылку значением.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Schwarz78 пишет:
Так я и спросил, потому что не понял. Вы уверены, что все понимают всё про ссылки? Я точно знаю, что личный опыт гораздо круче чужого, но чужой опыт - ещё круче, когда осознанный.
Видите ли. Я не работаю программистом. Но даже здесь на форуме от многих я получаю упреки, что я паршиво знаю не только ссылки, но и кучу аспектов Си и железа. И это при том что я регулярно хоть что-то изучаю. Но все осознать не реально , по крайней мере мне.

ПС: Тот канал все же регулярно смотрите. Это  сэкономит ваше время.

ВН
Offline
Зарегистрирован: 25.02.2016

.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78 пишет:

Да, int foo( int& x, int& y ), и вызываем if( foo( x, y ) ) {}. А х и y - мои переменные. А foo может их легко поменять.

А кто или что не даёт написать const перед тем(и) параметром, который менять нельзя? Тогда на попытку поменять компилятор обругается. Собственно и с указателями такой же приём работает.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Вот смотрите. Я никогда не был программистом. Мне пришлось. Я не собирался изучать Си. Мне пришлось. Теперь я просто увидел ардуино, а тут авр гцц. И вот я вижу людей, близких мне по духу, но ушедших далеко вперёд. Могу я спросить?

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Да, я уже понял, что компилятору надо намекать. Но намекните всё же, зачем вы используете ссылки каждый день, или вы их нет?

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Это видимо просто объяснить. Я знаю язык даже не с99, а наверное предыдущий, когда уже аргументы перестали определять перед фигурной скобкой. Этож контроллеры)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Schwarz78 пишет:

Да, я уже понял, что компилятору надо намекать. Но намекните всё же, зачем вы используете ссылки каждый день, или вы их нет?

Блин . Как только ваши проекты пересекут больше 10000 строк. Или начнете писать библиотеки для всех, без ссылок не обойдетесь. А для того что бы помигать светодиодом не всегда надо даже знания Си.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Как я вас понимаю. Я тоже надуваюсь, как только кому-то интересно то, что знаю я.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78 пишет:
Могу я спросить?
Простите, не понял, я Вас чем-то обидел, или на какой-то вопрос не ответил?

Schwarz78 пишет:

намекните всё же, зачем вы используете ссылки каждый день

Ну, как зачем, ну вот надо мне передать в фунцкию сложный объект. Как передавать?

1. По значению - это значит создавать его копию, проводить всю инициализацию и т.п. Посмотрите вот эту тему, особенно, начинаю с заголовка "Неоправданная передача параметра функции по значению"

2. Передавать указатель. Ну, во-первых, нарываемся на громоздкий синтаксис разыменования, а во-вторых, теряем всякую защиту

3. По ссылке и полная защита, и никаких синтаксических наворотов.

Вот, потому и используем.

Указатель я передаю, когда мне надо работать с массивом. А когда с единичным объектом - зачем?

axill
Offline
Зарегистрирован: 05.09.2011

Schwarz78 пишет:

Я знаю язык даже не с99, а наверное предыдущий, когда уже аргументы перестали определять перед фигурной скобко

о сколько вам открытий чудных...

я тоже с 90-х знал тот еще с++ и какое же было мое откровение когда мне посоветовали и я стал изучать с++11 (стандарт 2011 года и все что было перед ним с начала 200х)

сейчас с++11 это самый доступный во многих компиляторах стандарт, хотя на той же ардуине где avr-g++ уже в значительной мере можно использовать с++17 и на подходе следующие стандарты

особенно в восторге от шаблонов, прощай препроцессор с его деревянной логикой

и кстати многое из того, что раньше решалось ссылками или указателями с шаблонами позволяет вообще без них обойтись (код в итоге может быть на машинном языке примерно тот же, но семантически ссылки не нужны)

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, собственно 11-ый - наше фсё. Там были последние крупные, революционные изменения (та же "семантика перемещения"). В 14-ом и 17-ом - так по мелочи. Хотя, ходят гнусные слухи, что к 20-му готовятся новые большие перемены в языке, причём такие, которые мне (и не мне одному) совсем не нравятся.

axill
Offline
Зарегистрирован: 05.09.2011

constexpr так понимаю это ++14, весьма полезна, что то еще

enum class удобна, и хотя вроде это с++11 почему то в IAR его нет

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

axill пишет:

constexpr так понимаю это ++14, весьма полезна, что то еще

Там она недоделанная. В 17-ом её довели до ума дополнив к if. Получилась "if constexpr" которая действительно полезна.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

ЕвгенийП пишет:

Простите, не понял, я Вас чем-то обидел, или на какой-то вопрос не ответил?

Конечно же нет.

Огромное спасибо всем, я не рассчитывал получить настолько развёрнутые ответы. Теперь, когда я вдруг пойму, что не могу дальше жить без ссылок, я всегда смогу прчитать эту тему, которая лучше любого учебника.