ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
29 марта
905240
fk0, легенда (18.02.2019 22:49, просмотров: 2541)
Тяжелое детство и восьмибитные игрушки никогда мне не давали понимания отличия ссылки от указателя. По-моему это просто адрес лежащий в регистре процессора. Другие концепции в голове не укладываются. А есть ли они? Вот пишут например "следует использовать всегда ссылку когда это возможно". Когда присваивается (указатель или ссылка) не в конструкторе, ясно, невозможно (использовать ссылку невозможно, только указатель получится). Но с другой стороны, когда аргумент используется для возврата значений, лучше использовать явно указатель, чем ссылку (на вызывающей стороне появляется намекающий амперсанд). Да и нормальной аргументации, то или другое -- нет. "Ссылка более понятна..." -- кому она там понятна, не знаю. Мне "адрес" более понятен. Тем более, когда есть указатель, его можно заменить на смартпоинтер (не меняя код, синтаксис остаётся, т.к. звёздочку и стрелочку перегрузить можно, а точку -- нет), а когда ссылка, то уже ни на что нельзя. Смысл, что мол поинтер может быть NULL мне непонятен. Мало ли способов прокастить результат rand() к любому виду ссылки... долго ли умеючи. Вот серьёзный аргумент: "Reference to const also accepts temporaries". Иногда это удобно, а иногда ровно наоборот. Подразумевается f(const Obj&) в прототипе и возможность вызова f(g(x)), где Obj& g(). Получается память под временный объект автоматически выделяется со ссылкой, а с указателем только руками такое сделать можно. Третьи пишут "Reference arguments should always be `const`", иначе используйте pointer. Это для выходных параметров. Но по идее, если не хочется получить во входном аргументе временный объект (см. выше) -- вполне себе решение использовать явно указатель и явно писать &var. Ещё на ту же тему, временные объекты, на которые была создана ссылка, существуют весь срок жизни ссылки (на уровне блока кода, ясное дело, до выхода из функции, не больше), что правда непонятно как использовать (почему бы просто не декларировать саму переменную нужного типа, а не ссылку). Аргументы: "ссылка - да, она более понятна. Потому что ты уверен, что..."
1) к тебе придёт объект. Как удостовериться, что это не nullptr ? Вызов-то позволяет. Даже если сегодня и сейчас ты на 100% знаешь что nullptr никаким образом прийти не может - то спустя какое-то время забудешь или даже всё может измениться. А тут - гарантия. Ну как const. Причём читая чужой код ты сразу эту гарантию воспринимаешь, без изучения всех возможных вариантов вызова.
Контраргумент -- в оч.умелых ручках это не важно, ссылка или указатель, одно превращается в другое лишним амперсандом или звёздочкой, незаметной такой. Можно вполне null в ссылке вернуть, например, если хочется, не сложно... Наконец можно комментарии или ассерты писать, мол указатель точно не нулевой.
2) вторая гарантия - этот объект не сумеют сохранить простым присваиванием. Максимум - передать в конструктор создаваемого другого объекта
По-моему вообще не аргумент, то же самое, что и с указателем. Могут сам указатель/ссылку сохранить когда нельзя. Нельзя ссылку присвоить? Можно из неё сделать указатель. Можно ссылку в конструктор объекта передать и прекрасно она там сохранится. За уши притянуто.
4) я бы ещё добавил константность. С указателями не так тривиально - может быть константный указатель на не константные данные или неконстантный на констатные или.... ну ты понял. С ссылкой всё проще.
Опять же кому? Понятно, сама ссылка всегда константная, а в остальном отличий-то нет. Ну слово const не слева от звёздочки а справа нужно не забывать. Или даже два раза const написать. Не велика проблема, если научиться писать не const type var (const char *var), а type const var (char const* var)... Большие минусы использования ссылок вместо указателей какие я вижу: 1) ссылки не позволяют их завернуть во что-то вроде смартпоинтера, т.к. неизбежна смена синтаксиса на всех нижележащих уровнях; 2) ссылку не положить в union без враппера (как минимум в структуру завернуть); 3) ссылку не использовать со стандартным контейнером без враппера (списки, массивы...); 4) использование врапперов меняет синтаксис/код "по всему коду", натыкается на невозможность неявной конверсии и т.п. 5) ссылка вместо указателя для возвращаемого значения (в аргументах функции) неоднозначна, коварна, провоцирует ошибки (хотя иногда именно это нужно); 6) возврат ссылки вместо указателя ведёт к проблемам с сохранением результата (например в контейнере -- можно сделать из ссылки указатель, но если там присваивание уже неявное, то проблемы), возвращать гарантированно не нулевой указатель на мой взгляд не зазорно; 7) использование ссылок в интерфейсах вместо указателя ведёт к перечисленным выше проблемам рано или поздно... Какие плюсы использования ссылок вместо указателей: 1) передача временного значения как аргумента с аллокацией памяти на стороне вызывающей функции (в эту же память можно вернуть значение), классика жанра: "const char* f(const Buffer& var = Buffer())", результат функции существует то точки с запятой; 2) ссылки могут использоваться для алиасинга (как указатель на конкретный элемент массива, на конретный член класса...); 3) вместо указателя, когда использование однозначно и ограничено (внутри функции, в приватных членах класса); 4) для передачи аргументов (но редко для возврата, см. пункт 5 выше) в функцию вообще. Вот тут тоже пишут: https://stackoverf …eferences-vs-pointers, с чем я совершенно несогласен. Откуда берётся safe/dangerous совершенно непонятно, я же знаю, внутри оно "адрес" в регистре процессора и обрабатывается одинаково. Единственное что, поменять ссылку нельзя случайно, но это ж явное действие, сложно делать такие ошибки. Использование смартпоинтеров, как там ниже рекомендуют, я тоже не согласен: они навязывают тип аллокатора (shared_ptr), делетера/деструктора (unique_ptr) и вообще владение объектом. А если не владеющий указатель, а если аллокатор не стандартный, а если тип аллокатора неизвестен? По-моему вопрос не владеющих указателей в C++ обойден стороной. В std::experimental есть observer_ptr разве что. weak_ptr не совсем то, т.к. опять привязано к стандартному аллокатору. Кто что может сказать на тему?
[ZX]