Сырые указатели в С++1х
От: cppguard  
Дата: 04.04.23 23:13
Оценка:
Если нужно передать владение указателем, то передают unique_ptr, если указатель без владения — сам указатель. Но почему во втором случае не передавать ссылку? Вопрос навеян кодовой базой LLVM и другими открытыми проектами.

Оба примера ниже отлично компилируются:

#include <memory>
#include <string>

int length1(const std::string& s)
{
    return s.length();
}

int length2(const std::string *s)
{
    return s->length();
}

int main() {
    auto s = std::make_unique<std::string>("test");
    return length1(*s) + length2(s.get());
}


причём, в режиме -O3 инструкции идентичны:
; length1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&): 
mov     eax, DWORD PTR [rdi+8]
ret
; length2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const*):
mov     eax, DWORD PTR [rdi+8]
ret
Re: Сырые указатели в С++1х
От: sergii.p  
Дата: 05.04.23 07:43
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Если нужно передать владение указателем, то передают unique_ptr, если указатель без владения — сам указатель. Но почему во втором случае не передавать ссылку? Вопрос навеян кодовой базой LLVM и другими открытыми проектами.


тоже такое замечал. То что я видел, передаются указатели зачастую в объекты, а не функции. Тогда есть реально проблема, что при хранении ссылки в структуре теряем конструктор копирования. По-хорошему надо переделывать на shared/weak но это зачастую избыточно и многим лень.
Ну и второй момент, что код взят из С.
Re: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 08:48
Оценка: +2
Здравствуйте, cppguard, Вы писали:

C>Но почему во втором случае не передавать ссылку?


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

P.S. На практикте иногда встречаются функции, которые вызываются много раз из разных мест. И вот, чтоб не делать проверки существования объекта много раз в точках вызова берут и запихивают эту проверку внутрь функции. Лично я такую практику не приветствую, даже если она позволяет сэкономить какое-то количество строк кода.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.04.2023 8:58 rg45 . Предыдущая версия .
Re[2]: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 10:18
Оценка: +2
Здравствуйте, sergii.p, Вы писали:

SP>Тогда есть реально проблема, что при хранении ссылки в структуре теряем конструктор копирования.


Конструктор не теряем, теряем только оператор присваивания:

http://coliru.stacked-crooked.com/a/98cab16e62e35a90

#include <iostream>

struct A
{
    int& x;

    void test() const { std::cout << "A: " << x << std::endl; }
};


int main()
{
    int i = 42;
    
    A a1 {i};
    A a2(a1); // OK

    a1.test(); // -> A: 42
    a2.test(); // -> A: 42

    // a2 = a1; // error: use of deleted function 'A& A::operator=(const A&)'
}


A, ну и конструирование по дефолту еще становится невозможным, но нередко это даже полезно.

Таким образом мы можем такие струкуры хранить даже в векторе, начиная с C++11 (при условии, что операция присваивания не применяется к самому контейнеру).
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.04.2023 11:08 rg45 . Предыдущая версия . Еще …
Отредактировано 05.04.2023 10:34 rg45 . Предыдущая версия .
Отредактировано 05.04.2023 10:29 rg45 . Предыдущая версия .
Отредактировано 05.04.2023 10:25 rg45 . Предыдущая версия .
Отредактировано 05.04.2023 10:24 rg45 . Предыдущая версия .
Re[2]: Сырые указатели в С++1х
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.04.23 14:20
Оценка: -4 :)
Здравствуйте, rg45, Вы писали:

R>ссылка всегда связана с объектом, а указатель может быть нулевым и эту возможность нужно корректно обработать.


Ссылка тоже может быть нулевой, если создана из нулевого указателя. Единственная разница — указатель можно незаметно обнулить, со ссылкой так не получится.
Re[3]: Сырые указатели в С++1х
От: Кодт Россия  
Дата: 05.04.23 14:43
Оценка: 8 (1) +2
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Ссылка тоже может быть нулевой, если создана из нулевого указателя. Единственная разница — указатель можно незаметно обнулить, со ссылкой так не получится.


Это неопределённое поведение.
И компилятор умеет на это закладываться.

Самое простое: "если указатель разыменовали, значит, он точно не нулевой, и все дальнейшие проверки можно поубирать".

Стреляет это двумя способами. Один при оптимизациях, а другой даже без оптимизаций.
void foo(Some* p) {
  Some& q = *p;
  if (!p) {
    ..... // код будет выброшен оптимизатором
  } else {
    ... q ... // сюда мы попадём - и, возможно, "попадём"
  }
}

и
class A { ... };
class B { ... };
class C : public A, public B { ... };

void p(C* c) {
  B* b = c;  // b = c ? (c со смещением базы) : nullptr
  if (b) { ... } else { ... }
}
void r(C& c) {
  B& b = c;  // &b = &c ? (&c со смещением базы) : (голое смещение базы)
  assert(&b);  // оптимизатор выкинет, но это неважно
  ...
}
Перекуём баги на фичи!
Re: Сырые указатели в С++1х
От: Кодт Россия  
Дата: 05.04.23 14:55
Оценка: 9 (3) +1
Здравствуйте, cppguard, Вы писали:

C>Если нужно передать владение указателем, то передают unique_ptr, если указатель без владения — сам указатель. Но почему во втором случае не передавать ссылку? Вопрос навеян кодовой базой LLVM и другими открытыми проектами.


Иногда это просто корпоративный стиль.
Например, в проекте Chromium все неконстантные out- и in-out-аргументов принято передавать именно по (заведомо ненулевому) указателю, чтобы подчеркнуть, что это out.
А передачу по значению / константной ссылке / xvalue оставляют для чистых in-аргументов, и выбор способа передачи определяется исключительно вопросами оптимальности.
Причина такой жести — в том, что так сложнее ошибиться в клиентском коде. Вызывающая сторона вынуждена явно показать, что вот этот аргумент — не передаёт, а принимает значение из вызываемой функции.
Моё имхо, что гуглохромовцы в этом вопросе занимаются анальным огораживанием, но им виднее. Контрибуторов в проект много, и проворонить какую-нибудь детскую ошибку с тяжёлыми последствиями — легко и дорогостояще.

Иногда это унификация. Полезно для шаблонов и просто для красоты.
Если код принимает такие, сякие и этакие указатели (а то и std::optional за компанию). Чтобы не переписывать и не колбасить всюду дважды — то ->, то .

Иногда даже без владения нужно обрабатывать пустые значения, которые для указателей выражаются как nullptr.

Конкретно в кодовую базу LLVM я не заглядывал, но, поскольку они дружат с гуглом, то вполне может быть, они приняли гугловский стиль.
Перекуём баги на фичи!
Re[3]: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 15:20
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Ссылка тоже может быть нулевой, если создана из нулевого указателя. Единственная разница — указатель можно незаметно обнулить, со ссылкой так не получится.


В well-formed программе не может. А ill-formed програмы, порождающие неопределенное поведение — это отдельная тема.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Сырые указатели в С++1х
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.04.23 15:44
Оценка:
Здравствуйте, rg45, Вы писали:

ЕМ>>Ссылка тоже может быть нулевой, если создана из нулевого указателя.


R>В well-formed программе не может. А ill-formed програмы, порождающие неопределенное поведение — это отдельная тема.


Какой смысл заострять на этом внимание? В контексте обсуждения нет никакой разницы — то ли программа ill-formed, то ли она well-formed, но "просто глючит".

Раз вообще возникает вопрос о замене указателя ссылкой — значит, ситуация, в которой указатель нулевой, но нигде нет ошибки, принципиально невозможна. И если где-то произойдет обращение по нулевому адресу, то и возникнет одно и то же исключение и в well-formed, и ill-formed программе, и это будет означать, что где-то допущена ошибка. Так что толку делать на этом акцент?
Re[5]: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 15:53
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Какой смысл заострять на этом внимание? В контексте обсуждения нет никакой разницы — то ли программа ill-formed, то ли она well-formed, но "просто глючит".


Разница принципиальная: в одном случае в корректной программе возникает нулевой указатель, который можно корректно обработать. В Win API, например, полно фунций, для которых передача нулевых укакзателей и дескрипторов разрешена спецификациями функций. А в другом случае программа уже породила неопределенное поведение и всякие дальнейшие проверки уже бессмысленны. Можно лишь обсуждать причины возникновения "битой" сслыки, но эта проблема уже точно за пределами контеста обсуждения.

ЕМ>Раз вообще возникает вопрос о замене указателя ссылкой — значит, ситуация, в которой указатель нулевой, но нигде нет ошибки, принципиально невозможна.


ИМХО, ничего это не значит. Человек, задающий этот вопрос, мог просто выпустить данный нюанс из виду.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.04.2023 16:01 rg45 . Предыдущая версия . Еще …
Отредактировано 05.04.2023 15:57 rg45 . Предыдущая версия .
Re[4]: Сырые указатели в С++1х
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.04.23 16:35
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Это неопределённое поведение.


А разыменование нулевого (или просто левого) указателя — определенное?

К>"если указатель разыменовали, значит, он точно не нулевой


Точнее, подразумевается ненулевым. А еще точнее — если после обработки исключения удалось вернуться обратно.

К>
К>  Some& q = *p;
К>  if (!p) {
К>


В обсуждаемой ситуации, когда указатель взаимозаменяем со ссылкой, нет никакого смысла его проверять, кроме как в assert'е, который должен ставиться до разыменования. А assert точно так же имеет смысл использовать и для проверки ссылок, переданных сверху и передаваемых дальше вниз, чтобы как можно раньше поймать ошибку.

К>
К>void p(C* c) {
К>  B* b = c;  // b = c ? (c со смещением базы) : nullptr
К>}
К>void r(C& c) {
К>  B& b = c;  // &b = &c ? (&c со смещением базы) : (голое смещение базы)
К>


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

Но дело даже не в этом, а в том, что без явных проверок программа все равно грохнется. Так какой смысл вникать в тонкости?
Re[6]: Сырые указатели в С++1х
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.04.23 16:45
Оценка: -4
Здравствуйте, rg45, Вы писали:

ЕМ>>Раз вообще возникает вопрос о замене указателя ссылкой — значит, ситуация, в которой указатель нулевой, но нигде нет ошибки, принципиально невозможна.


R>Человек, задающий этот вопрос, мог просто выпустить данный нюанс из виду.


Как его можно выпустить из виду? Идеологически указатель отличается от ссылки только тем, что допускает нулевое (или любое другое невалидное) значение в качестве "альтернативного", которое можно использовать для передачи дополнительной информации сверх собственно указываемого значения. Если указатель где-то преобразуется в ссылку, то эта дополнительная информация теряется.

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

Если же кто-то не понимает столь базовых вещей, то он хоть с указателями, хоть со ссылками наплодит кучу ошибок на ровном месте. Ж)
Re[7]: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 17:28
Оценка: +4 -1 :))) :)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Как его можно выпустить из виду? Идеологически указатель отличается от ссылки только тем, что допускает нулевое (или любое другое невалидное) значение в качестве "альтернативного", которое можно использовать для передачи дополнительной информации сверх собственно указываемого значения. Если указатель где-то преобразуется в ссылку, то эта дополнительная информация теряется.

ЕМ>Соответственно, если программа использует хоть указатели, хоть ссылки сугубо для косвенной адресации, для нее нет никакой разницы от замены одних на другие. Если же она хоть где-то проверяет значение указателя — значит, дополнительная информация в нем передаваться может, и на ссылку он может заменяться лишь после проверки.
ЕМ>Если же кто-то не понимает столь базовых вещей, то он хоть с указателями, хоть со ссылками наплодит кучу ошибок на ровном месте. Ж)

Слушай тебе не надоело генерить всякий бред? И по поводу "базовых вещей" — уж чья бы мычала.

P.S. Тут где-то Shmj шарахается неподалеку — вот это собеседник для тебя — в самый раз. Можете скипидарить мозги друг другу до одновременного огразма.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.04.2023 17:30 rg45 . Предыдущая версия . Еще …
Отредактировано 05.04.2023 17:30 rg45 . Предыдущая версия .
Отредактировано 05.04.2023 17:29 rg45 . Предыдущая версия .
Re[8]: Сырые указатели в С++1х
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.04.23 17:41
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>тебе не надоело генерить всякий бред?


Бред — это увлекаться формализмом там, где он совершенно не требуется.

R>по поводу "базовых вещей" — уж чья бы мычала.


У нас с Вами несколько разное понимание "базовых вещей". Вам больше нравится четко помнить тонкости семантической правильности, соответствия стандартам и т.п., а мне — хорошо понимать, как языковый код преобразуется в машинный и работает там. Поскольку от собеседований, работы в команде и подобного я был избавлен изначально, первое мне тупо никогда не требовалось, а вот без второго никак.
Re[9]: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 17:44
Оценка: -1 :)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>У нас с Вами несколько разное понимание "базовых вещей". Вам больше нравится четко помнить тонкости семантической правильности, соответствия стандартам и т.п., а мне — хорошо понимать, как языковый код преобразуется в машинный и работает там. Поскольку от собеседований, работы в команде и подобного я был избавлен изначально, первое мне тупо никогда не требовалось, а вот без второго никак.


Да я в курсе, что все вокруг олени, один ты Дед Мороз.

P.S. Тебе бы к психологу — для корректировки самооценки.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.04.2023 17:45 rg45 . Предыдущая версия .
Re[9]: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 17:56
Оценка: -1 :)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>У нас с Вами несколько разное понимание "базовых вещей". Вам больше нравится четко помнить тонкости семантической правильности, соответствия стандартам и т.п., а мне — хорошо понимать, как языковый код преобразуется в машинный и работает там. Поскольку от собеседований, работы в команде и подобного я был избавлен изначально, первое мне тупо никогда не требовалось, а вот без второго никак.


Свое "хорошее понимание" ты тут не раз уже демонстрировал. Что ни топик, то хит: http://rsdn.org/forum/cpp.applied/8453548.1
Автор: Евгений Музыченко
Дата: 21.01.23
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[7]: Сырые указатели в С++1х
От: B0FEE664  
Дата: 05.04.23 17:58
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Как его можно выпустить из виду? Идеологически указатель отличается от ссылки только тем, что допускает нулевое (или любое другое невалидное) значение в качестве "альтернативного", которое можно использовать для передачи дополнительной информации сверх собственно указываемого значения.


Идеологически указатель отличается от ссылки очень сильно: ссылка — это второе имя объекта, указатель — это другой объект.
И каждый день — без права на ошибку...
Re: Сырые указатели в С++1х
От: T4r4sB Россия  
Дата: 05.04.23 18:01
Оценка: -1
Здравствуйте, cppguard, Вы писали:

C>Если нужно передать владение указателем, то передают unique_ptr, если указатель без владения — сам указатель. Но почему во втором случае не передавать ссылку? Вопрос навеян кодовой базой LLVM и другими открытыми проектами.


C>Оба примера ниже отлично компилируются:



C>причём, в режиме -O3 инструкции идентичны:


Потому что ты написал не то. В случае со std::string надо передавать std::string_view, а в случае с std::unique_ptr надо передавать указатель на внутренний ресурс при помощи get()
Re[8]: Сырые указатели в С++1х
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.04.23 18:17
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>ссылка — это второе имя объекта, указатель — это другой объект.


Не "это" ("является"), а "может рассматриваться в качестве", и то лишь на самых начальных этапах изучения, чтобы сформировать общую картину языка. В большинстве же практических применений никуда не деться от того, что ссылка — это самостоятельный объект, занимающий место в памяти, копируемый при передаче, подверженный непреднамеренным искажениям и т.п. Так что под "идеологически" я подразумевал сугубо идеологию работы с ними.
Re[8]: Сырые указатели в С++1х
От: rg45 СССР  
Дата: 05.04.23 18:20
Оценка: :))
Здравствуйте, B0FEE664, Вы писали:

ЕМ>>Как его можно выпустить из виду? Идеологически указатель отличается от ссылки только тем, что допускает нулевое (или любое другое невалидное) значение в качестве "альтернативного", которое можно использовать для передачи дополнительной информации сверх собственно указываемого значения.


BFE>Идеологически указатель отличается от ссылки очень сильно: ссылка — это второе имя объекта, указатель — это другой объект.


Я вот думаю, может, зря мы тогда Shmj отпугнули? Сейчас бы посадили бы их вдвоем где-нибудь в уголочке, пускай бы игрались.
--
Не можешь достичь желаемого — пожелай достигнутого.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.