LINUX.ORG.RU

юнионы в C++

 


2

4

Пишу телегу против плюсов. В связи с этим вопрос - насколько широко в плюсах используются нуль-терминированные строки, юнионы, неумные указатели и всё такое плохое, что делает Си опасным языком.

Даже интересует не столько то, насколько они используются в существующих программах, а есть ли примеры программ, где хорошие средства плюсов сконсолидировались и поставили заслон от опасных конструкций Си, позволив полностью избежать их использования и избавиться от типичных ошибок Си. Можно ли так написать что-то существенно сложное? Сделано ли это в любимых библиотеках (Буст, QT и иже с ними)? Вторая часть вопроса - это неопределённое поведение. В Си его много. Это подаётся как фича, но с точки зрения безопасности это дыра. Меньше ли неопределённого поведения в С++?

Есть две полярные точки зрения на вопрос:

а) С++ перекрывает Си, поэтому там всё сделано по-другому, поэтому безопасность выше б) С++ - наследник Си и в целом наследует его недостатки.

Поскольку я мало пишу на Си и ещё меньше на Си++, у меня нет сложившегося мнения на эту тему. А у ЛОРа наверняка есть мнение, даже несколько.

★★★★★

Последнее исправление: xaizek (всего исправлений: 4)
Ответ на: комментарий от Crocodoom

Лучше не надо, byko3y таки хороший флеймогенератор

Как я понимаю, он ищет формулу успеха. Легко сказать, что Биллу Гейтсу помогала семья. Тут всё понятно. А как пришли к успеху Бьёрн Страуструп или Гвидо Ван Россум? Предполагать что дело в их исключительной гениальности, доставшейся по наследству, бесполезно. В таком случае они не сильно отличаются от Гейтса. Соответственно, ищутся дополнительные признаки. Так возникает «продажник». При этом byko3y оставляет оппонентам возможность доказать, что дело всё-таки в программистской гениальности. Но вместо этого идёт подсчёт 300 строчек кода.

А комитеты и сообщества разработчиков ещё интереснее. Как получилось, что Гвидо изгнали из сообщества разработчиков Питона? Если всё мерить через программистскую гениальность, то получается, что там остались какие-то более великие гении. Но почему они не так известны, к успеху не пришли?

Kogrom
()
Ответ на: комментарий от Kogrom

Как получилось, что Гвидо изгнали из сообщества разработчиков Питона?

Так он же сам ушёл. А сейчас работает в Microsoft

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Он пошел работать в майкрософт от скуки. Заскучал на пенсии.

rupert ★★★★★
()
Ответ на: комментарий от eao197

В C++ если объект B не является частью объекта A, то константность объекта A на B не распространяется

Однако, std:;vector ссылается на динамический массив, таки распространяя константность на оный. В языке D это наконец сделано грамотно, то есть, если нельзя менять объект, то должно быть нельзя менять все данные, на которые он ссылается, без исключений. Если «иногда можно менять, иногда нельзя», то на const нельзя полагаться.

Я нагуглил пару статеечек:

http://jmdavisprog.com/articles/why-const-sucks.html

Ключевые выжимки в контексте тхреада:

* const serves as documentation that the programmer intends for an object to be treated as logically const.
* const protects against the accidental mutation of objects.

с уточнением

I can think of exactly one case in my entire career where const actually prevented a bug, and that's when I got the arguments to the STL's copy function backwards

Поразительно то, что почти полгода назад я писал DarkEld3r-у про const примерно то же самое, даже не имея толком опыта писания на крестах, но человек, который начинал с крестов, спустя годы пишет то же самое. Потому не нужно рассказывать мне про «старый пердун, отрицающий новую для себя технологию». Проблема очевидна, просто те, кто слишком долго пишут на крестах, перестали ее замечать.

Но как же тогда писать? Скажите нам, как, научите, дайте набор правило. Их есть у нас:

https://quuxplusone.github.io/blog/2022/01/23/dont-const-all-the-things/

Краткий пересказ-перевод:

  • используйте const только там, где это действительно необходимо, не нужно вешать const на всё попало (как это пропагандируют отдельные гуру), вы пишите не на Rust, лишний const в том числе может помешать оптимизатору;
  • не используйте const в локальных переменных, это overkill, вы и так видите все использования этих переменных;
  • не используйте const для возвращаемых из функции значений. С появлением move semantic последние адвокаты возврата по ссылке заткнулись и признали, что возврат по значению лучше абсолютно всем. Возвращать нужно либо значение, либо неконстантную ссылку на значение (например, элемент массива);
  • не используйте const для аргументов функции, за исключением передачи по константной ссылке (const T&). Вы на самом деле никогда не хотели передавать константное значение, потому что вы все равно копируете его, а const, опять же, может мешать оптимизатору. И маленькое замечание от автора, не имеющее отношения к const: для выходных аргументов используйте передачу по указателю, а не по ссылке — так лучше видно намерение, это в каком-то смысле такая же документация-соглашение, как и в случае const;
  • объявляйте константными методы, которые не собираются менять свой объект (эквивалент const T&);
  • все эти «не» относятся только к «привнесенной» константности. То есть, если вы работаете с константами «const char *», то вы так их и объявляете. Замечания выше касаются только const, прилепленного поверх неконстантных значений;
  • не используйте const для полей простых структур-значений. Это создает проблемы с копирование-перемещением на ровном месте;
  • не используйте const для полей сложных классов — для этой функции есть private/public.

Последние два пункта в значительной степени повторяют мои аргументы полугодовой давности по поводу того, что бинарный const плохо налазит на сложносоставные структуры, где логическая константность подразумевает возможность менять поля. А поскольку const — это прежде всего комментарий, то он должен упрощать чтение и писание кода, а не затруднять его. Если const привносит трудности, то его нужно выбрасывать и делать более высокоуровневые интерфейсы, аля const_iterator.

byko3y ★★★★
()
Ответ на: комментарий от eao197

В контексте предыдущего сообщения снова возвращаемся к: юнионы в C++ (комментарий)

struct list_node {
  const char * m_payload;
  list_node * m_prev;
  list_node * m_next;
};

Ты привел антипаттерн. В Rust с этим можно жить, но в C++ этот const помешает делать банальные присвоения-копирования. Хотя, я пессимистично настроен даже к mutable: если у вас структура изменяемая, то она изменяема, не нужно натягивать сову на глобус.

Ситуация с контейнерами, которые могут быть применены для константных, неконстантных, и смешанных значений, по прежнему достаточно сложная. Да, если кода немного, то можно идти по пути: юнионы в C++ (комментарий)

Традиционный подход такой: когда вам нужна get_second в первый раз вы пишите ее максимально простой, именно такой какой она должна быть здесь и сейчас.
Когда вам get_second нужна во второй раз, то вы смотрите чем ситуации применения get_second отличаются.

Но если кода уже много, то перекраивать всю либу для поддержки обобщенных аргументов может оказаться больно и унизительно. Например, мы сделали целую либу, которая работает с массивом «char *», и везде ее использовали для «char *» значений (условно это эквивалент vector<char*>), и успешно использовали эту либу еще для кучи кода (тру стори, между прочим). Не то, чтобы контейнер сам менял значение по указателю — просто он использовался для организации строк, которые меняются во внешнем коде: на одном этапе работы программы в контейнер закладываются значения, контейнер передается на другой этап, на другом этапа значения читаются-изменяются, потом третий этап, четвертый...

И тут в один день оказалось, что нам иногда нужно туда пихать значения «const char*», то есть настоящие константы. «Давай по новой, Миша, всё не так»? Любой vector<T*> не подходит, потому что константность смешанная. В идеально надежной реализации нужно применить тэгирование и проверку в рантайме: потребитель, который меняет значение, обращается только к значениям, положенным в контейнер как «char *», а read-only потребитель может обращаться к любым значениям. Если же мы экономим на рантайме, то делаем const_cast и дальше пользуемся либой, как ни в чем ни бывало. А больше никак, поскольку у нас код, который кладет значения, удален от кода, который эти значения потребляет, и всё держится только на честном слове программиста, что он не будет класть «const char *» в контейнер, значения которого будут потом изменены.

Как ни странно, именно этот последний инвариант можно статически проверять, но для этого нужно вспомнить, что const — это очень примитивный инструмент и в языке есть более высококоуровневые абстракции. Например, создать класс или просто набор функций, которые внутри хранят значения с какой угодно константностью, но наружу подают это в виде набора интерфейсов:

  • интерфейса добавления в вектор смешанных значений push_back(const char*), с которого можно брать только итератор по const char*;
  • писателя строго изменяемых значений push_back(char*), на который можно взять любой итератор.

const vector<T> здесь не подходит, потому что на нем нужно делать push_baсk на всех сценариях.

struct app_context_t {
  logger_t & m_logger;
  const app_args_t & m_args;
  ...
}

Ссылки в структурах (не путать с указателями) — это еще больший рак. Как это дело конструировать/копировать/перемещать?

Если уж вы хотите для своих типов сделать транзитивную константность в том числе и для ссылок/указателей

Напоминаю, что речь шла не про какие-то абстрактные указатели — пример был про конкретный shared_ptr. Это как бы попытка сделать человечный подсчет ссылок на разделяемую строку, чтобы константный указатель не требовал копирования, как это уже давно реализовано во многих ЯП на уровне стандартной либы, но только не в C/C++.

byko3y ★★★★
()
Ответ на: комментарий от eao197

а поскольку в C++ константы уже зарезервированы для названия переменных, то для названия переменных задействовали термин «буквальное значение».

О боже, какую хрень я только что прочитал?

Да, я ошибся словом, но это несложно сделать в языке, в котором переменные бывают константами.

void f(int && v) {
std::cout << «Temporary int: » << v << std::endl;
}

int main() {
f(MY_VAL);
}

Здесь буквальная константа используется для инициализации временной истинной переменной. Это магия неявных копирований-перемещений.

byko3y ★★★★
()
Ответ на: комментарий от mike77

Ты как-то спорил с местным быдланом про тойоту. Может быть интересно будет: https://blogs.fsfe.org/agger/2022/05/12/devops-inspiration-from-toyota-produc...

Спасибо большое за ссылку. К сожалению, автор в стопятсотый раз ничего не понял и снова оценил вещи поверхностно, эдакий реверс-каргокульт. Ну типа когда работники с Дюпона заболевают тяжелыми формами околораковых заболеваний после работы на некоторых производствах, а им потом отказывают в каких-то серьезных компенсациях — это нормально, а когда работник тойоты в условное свободное время посещает некие мероприятия по повышению квалификации, которые ему не полностью оплачиваются (но оплачиваются) — это сразу никуда не годится, эксплуатация рабского труда. Когда на Deepwater Horizon под давлением руководства нарушено бесчисленное число регламентов и по итогу платформа сгорает с кучей работников — это нехорошо, но бывает. А если от болезней, связанных с переработкой, умирает кто-то на тойоте — это «тёмная правда японской индустрии». А я вот слышал истории о том, как в западной конторе заставляли по 12 часов работать кодеров. Или Амазон, который так же загоняет своих сотрудников.

Потому я говорю, что автор на самом деле ничего не понял, в этом плане японские заводы ничем не отличаются от американских или китайских. Настоящее отличие заключается в том, что в Японии работник относится к заводу как к своей личной общине: он обязан ей хорошо работать, но и община не может просто выгнать работника. Да-да, с Тойоты не увольняют, даже когда дела в компании идут очень плохо. В западной компании нормально ровно в 17-00 уходить с рабочего места, «меня ничего не волнует, мне нужно сына забрать из садика». То есть, это просто наемный работника, как в совке, который формально выполняет работу от звонка до звонка и получает фиксированную оплату за это.

Вот эти вот абстрактные идеалы Agile про «Build projects around motivated individuals» в принципе не работают в типичных западных компаниях, потому что сотрудникам заранее безразлично всё, что происходит в компании. Это может доходить до такого трешака, что бизнес-процессы, будь то производство или разработка, скатываются в полное говно, чудовищно неэффективное, как на Porsche, в котором 80% времени на конвеере работники играли в маугли, карабкаясь по стелажам за инстурментами-приспособами-деталями — и их это устраивало, потому что платили им среднюю для региона ЗП более-менее независимо от результата (за отработанное время). От сотрудников тойоты же, пусть и не ото всех, но можно ждать некоторых усовершенствований, потому что они чувствуют, что это их завод. После многочисленных итераций усовершенствования конвеера конечный результат можно просто каргокультировать — получится может быть и хуже, чем в тойоте, может быть не так эффективно за счет переработок, но все равно намного лучше, чем под руководством человека из банкирско-спекулянтской тусовки или наемного манагера, действующего по принципу «нанимать еще более тупых подчиненных, чтобы я выгодно смотрелся на их фоне».

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от byko3y

Поразительно то, что почти полгода назад я писал DarkEld3r-у про const примерно то же самое, даже не имея толком опыта писания на крестах

И этим всё сказано - не умею, но мнение имею. Ню ню.

bugfixer ★★★★★
()
Ответ на: комментарий от byko3y

Однако, std:;vector ссылается на динамический массив

Потроха std::vector – это потроха std::vector, к видимой пользователю семантике они имеют только косвенное отношение (пользователь должен осознавать, что нижележащее хранилище может расти или уменьшаться).

http://jmdavisprog.com/articles/why-const-sucks.html

Во-первых, вы притаскиваете какие-то мнения из интернета и хотите, чтобы их воспринимали как истину в последней инстанции. Схерали, пардон май френч?

Во-вторых, вы в упор не понимаете о чем я вам толкую. Я не защищаю C++ный const, не утверждаю, что он идеален, не говорю о том, что лучше ничего не может быть.

Я в очередной раз вынужден повторить простую вещь: в C++ есть const, он вот такой. Все. В обозримое время другим он не будет.

У вас, как у пользователя, есть возможность осознать это и научиться применять const так, чтобы он приносил вам пользу.

Вместо этого вы истерите здесь о том, какое const говно, как вы не можете в const и какие все редиски, что не понимают ваши страдания.

I can think of exactly one case in my entire career where const actually prevented a bug

У каждого свой опыт. Мне компилятор раз в 3-4 месяца бьет по рукам за то, что я забываю про const. Т.е. указывает мне на мои просчеты. Что уже оправдывает существование const.

Не говоря уже про то, что const заметно упрощает разбирательство с кодом.

https://quuxplusone.github.io/blog/2022/01/23/dont-const-all-the-things/

quuxplusone известный C++ный блоггер, но это не гарантирует того, что он на 100% прав. В частности, по поводу:

не используйте const для полей простых структур-значений. Это создает проблемы с копирование-перемещением на ровном месте;

не используйте const для полей сложных классов — для этой функции есть private/public.

Он конкретно неправ (а по простому тупо жиденько обосрался). И это не только мое мнение.

где логическая константность подразумевает возможность менять поля

Вам сперва со своими тараканами в голове нужно разобраться. А потом уже C++ный const говном обмазывать.

eao197 ★★★★★
()
Ответ на: комментарий от byko3y

Здесь буквальная константа используется для инициализации временной истинной переменной. Это магия неявных копирований-перемещений.

Пруфы?

eao197 ★★★★★
()
Ответ на: комментарий от LongLiveUbuntu

Ну в грамотных коллективах за шаблоны бьют по лапкам

И в команде разработки boost?

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

byko3y ★★★★
()
Ответ на: комментарий от byko3y

но в C++ этот const помешает делать банальные присвоения-копирования

Конкретно этот ничему не помешает. Матчать таки выучите.

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

Разговор на эту тему можно будет продолжить только когда вы приведете хоть сколько-нибудь разумный пример.

Пока вы ничего родить не смогли.

И тут в один день оказалось, что нам иногда нужно туда пихать значения «const char*», то есть настоящие константы.

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

Ссылки в структурах (не путать с указателями) — это еще больший рак.

«Тупые переливания из пустого в порожнее от byko3y – это еще больший рак.»

Оба утверждения одного уровня достоверности и значимости. Никакой конструктивности разговору не добавляют от слова совсем.

Как это дело конструировать/копировать/перемещать?

Элементарно.

eao197 ★★★★★
()
Ответ на: комментарий от Kogrom

А как пришли к успеху Бьёрн Страуструп или Гвидо Ван Россум?

Прежде всего сделали работающий инструмент.

А потом именно им повезло. Звезды так сложились.

У кого-то не сложилось, хотя новых языков создают множество. Только что-то взлетает как C++, Python или Java. Что-то взлетает, но не сильно (вроде Ruby, Scala или Rust).

Что-то используется, но известно лишь единицам (например, Pike или Gosu).

А что-то вообще умирает, в том числе и от безвестности.

Рецепта достижения успеха нет. Но необходимая составляющая – это сделанный работающий инструмент, удобный хотя бы для своих создателей.

Этим и Страуструп, и ван Россум сильно отличаются от byko3y.

Так возникает «продажник». При этом byko3y оставляет оппонентам возможность доказать, что дело всё-таки в программистской гениальности.

Это не так работает.

Я могу высказать мнение о том, что byko3y психически больной человек, страдающий от несостоятельности в своей профессиональной деятельности, что и заставляет его писать простыни откровенной ерунды на LOR-е.

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

При этом я оставляю оппонентам доказать, что дело все-таки в их (т.к. byko3y и Kogrom) программисткой гениальности.

Ну и как вам, все нормально в таком подходе?

Но вместо этого идёт подсчёт 300 строчек кода.

Про это я уже объяснял. Если вам что-то осталось непонятно, то скажите что именно, постраюсь объяснить подробнее.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Здесь буквальная константа используется для инициализации временной истинной переменной. Это магия неявных копирований-перемещений

Пруфы?

https://gcc.godbolt.org/z/747bv8Yfn

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

byko3y ★★★★
()
Ответ на: комментарий от eao197

Но вместо этого идёт подсчёт 300 строчек кода.

Про это я уже объяснял

Справедливости ради - я видел и хуже. Мне кажется - это совсем не принципиально. Но вот в Тулу со своим самоваром не стОит, это правда.

bugfixer ★★★★★
()
Ответ на: комментарий от eao197

Теперь все тоже самое для interger literal

Целочисленный литерал вшит в цомпилятор. Свой float нельзя написать. У меня в коде был целочисленный литерал, если что, так что я не понимаю, о чем вообще твой вопрос.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

У меня в коде был целочисленный литерал, если что, так что я не понимаю, о чем вообще твой вопрос.

Вы утверждаете, что для случая с int-ом компилятор создает временный экземпляр переменной типа int, которой присваивается значение константы.

Вот это не мешало бы доказать.

Поскольку лично я не вижу причин, почему бы компилятору сразу не создать мутабельный экземпляр int с нужным значением, без каких либо констант.

Это все о том, что define в C++ никогда не использовался для задания констант. define – это всегда про текстовую подстановку, что к константности отношения не имеет.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Потроха std::vector – это потроха std::vector, к видимой пользователю семантике они имеют только косвенное отношение

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

Я в очередной раз вынужден повторить простую вещь: в C++ есть const, он вот такой. Все. В обозримое время другим он не будет
У вас, как у пользователя, есть возможность осознать это и научиться применять const так, чтобы он приносил вам пользу.

А я что, спорю? Но ты сам же приводишь антипаттерны, как не нужно использовать const в C++... таким, какой он есть и другим не будет. Не путать «можно» и «нужно». Можно делать const_cast на любом указателе, каком захочется, но не нужно, потому что это затрудняет поддержку кода. Можно лепить const на поля структур, но не нужно, поскольку это затрудняет поддержку кода.

Не говоря уже про то, что const заметно упрощает разбирательство с кодом

Да, как и любые другие комментарии.

Он конкретно неправ (а по простому тупо жиденько обосрался). И это не только мое мнение

А то, что ссылочные и константные поля не нужны — это тоже не только его мнение:

https://lesleylai.info/en/const-and-reference-member-variables/

От них сплошные проблемы и никаких преимуществ.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Ссылки в структурах (не путать с указателями) — это еще больший рак. Как это дело конструировать/копировать/перемещать?

Начнём с того что любые ссылки immutable. Вы тупо даже близко не понимаете плюсовые типы, и самое главное - зачем и почему сделано именно так.

bugfixer ★★★★★
()
Ответ на: комментарий от eao197

но в C++ этот const помешает делать банальные присвоения-копирования

Конкретно этот ничему не помешает. Матчать таки выучите

Да, ошибся, там нет проблемы. Но ты когда-то писал про то, что сделать часть полей константными.

Разговор на эту тему можно будет продолжить только когда вы приведете хоть сколько-нибудь разумный пример.

Пока вы ничего родить не смогли

Уже два примера привел — всё не то и всё не так. Ок.

Ссылки в структурах (не путать с указателями) — это еще больший рак.

«Тупые переливания из пустого в порожнее от byko3y – это еще больший рак.»

Ответил по поводу ссылок выше:
юнионы в C++ (комментарий)
https://lesleylai.info/en/const-and-reference-member-variables/

byko3y ★★★★
()
Ответ на: комментарий от byko3y

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

Не распарсил. Если вы хотите сами сделать транзитивную константность, то вам никто не помешает.

Тут вопрос в том:

a) насколько это целесообразно;

b) насколько затем будут благодарны те, кто будет сопровождать написанный вами код.

Учитывая продемонстрированные вами умственные способности я думаю, что серьезные претензии будут по каждому из пунктов.

Но ты сам же приводишь антипаттерны, как не нужно использовать const в C++

С этого места поподробнее.

Можно делать const_cast на любом указателе

Нет. В общем случае const_cast – это UB.

Да, как и любые другие комментарии.

Нет. Комментарии не проверяются ни компилятором, ни анализаторами кода.

От них сплошные проблемы и никаких преимуществ.

– Я не люблю котов, от них запах и шерсть…

– Да вы, батенька, просто не умеете их готовить.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Поскольку лично я не вижу причин, почему бы компилятору сразу не создать мутабельный экземпляр int с нужным значением, без каких либо констант

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

Это все о том, что define в C++ никогда не использовался для задания констант

Вот сейчас грепнул Cfront 1.0 — валом констант в дефайнах. «Никогда»?

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Вот сейчас грепнул Cfront 1.0 — валом констант в дефайнах. «Никогда»?

Это не константы. Это литералы. Именованные посредством define.

eao197 ★★★★★
()
Ответ на: комментарий от byko3y

Уже два примера привел — всё не то и всё не так. Ок.

Ни одного примера, который можно было бы обсудить предметно не было.

И, я думаю, другие читатели этой темы разделят мое мнение.

eao197 ★★★★★
()

Что же будет, когда в букваре начнутся шаблоны, если какая-то элементарщина рождает простыни на десятки страниц. Очередной перл про копирование указателя на константу - повеселил. Эксперт трехмесячный.

kvpfs ★★
()
Ответ на: комментарий от eao197

Если вы хотите сами сделать транзитивную константность, то вам никто не помешает

Ну в STL по итогу сделали «через раз». Я уже выше писал, что на самом деле они просто сделали ее там. где им было удобно, и предпочли не делать там, где это неудобно сделать. Что есть вполне логично.

Но ты сам же приводишь антипаттерны, как не нужно использовать const в C++

С этого места поподробнее

Я ошибся с тем примерном «const char *», но вот твой пример с

struct app_context_t {
logger_t & m_logger;
const app_args_t & m_args;
...
}

это чистое попадание. Ссылкам (по крайней мере вернего уровня) в полях объектов вообще нечего ловить.

В общем случае const_cast – это UB

А вот я утверждаю, что в моих сорцах везде const_cast будет использоваться только корректно, я его не буду использоваться в случаях, приводящих к UB.

Комментарии не проверяются ни компилятором, ни анализаторами кода

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

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от byko3y

А то, что ссылочные и константные поля не нужны — это тоже не только его мнение:

https://lesleylai.info/en/const-and-reference-member-variables/

Тот самый случай, когда «смотрю в книгу, вижу фигу».

Вам нужно внимательно перечитать эту статью. Там все по делу написано. Хотя, наверное, и слишком коротко.

eao197 ★★★★★
()
Ответ на: комментарий от Crocodoom

Так он же сам ушёл.

Однако он ушёл со словами:

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

Я предполагаю, что развитие Питона сейчас идёт по двум разнонаправленным векторам: с одной стороны надо быть маленьким встраиваемым язычком с динамической типизацией, с другой стороны - серьёзным инструментом для разработки крупных приложений. Это противоречие сложно разрешить. Поэтому Гвидо мог таким путём уклониться от решения этой задачи, сославшись на недопонимание других разработчиков.

Kogrom
()
Ответ на: комментарий от eao197

Это не константы. Это литералы. Именованные посредством define

Весь исходный код — это что-то именованное чем-то. Или ты думаешь, что процессор при выполнении программы у тебя имена переменных прямо так и читает? Дефайн, по крайней мере для примитивных типов, рождает такие же константы, как и constexpr.

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от eao197

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

Другие читатели пока молчат по этому поводу. Если тебя не устраивают примеры — это твое дело.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Ну в STL по итогу сделали «через раз».

И?

но вот твой пример с struct app_context_t это чистое попадание.

Схерали? А мысль о том, что app_context_t изначально не предназначен для копирования, в голову не приходила?

Ссылкам (по крайней мере вернего уровня) в полях объектов вообще нечего ловить.

А byko3y нечего ловить в программировании.

И, мне кажется, в моем утверждении правды таки больше.

А вот я утверждаю, что в моих сорцах везде const_cast будет использоваться только корректно, я его не буду использоваться в случаях, приводящих к UB.

Доказательства уровня «мамой клянусь», конечно же, имеют право на существование и даже широко используются при программировании на C++.

Но хорошего в этом нет.

А я утверждаю, что проверка константности в C++ настолько дырява, настолько ненадежна, что по const-комментариям производится только крайне ограниченная проверка, без которой, в общем-то, можно жить

Без мозгов в голове тоже жить можно, но зачем?

eao197 ★★★★★
()
Ответ на: комментарий от kvpfs

Что же будет, когда в букваре начнутся шаблоны, если какая-то элементарщина рождает простыни на десятки страниц. Очередной перл про копирование указателя на константу - повеселил. Эксперт трехмесячный.

Смехуечка по теме:
https://twitter.com/yossikreinin/status/1119617899012993025

Most of C++ criticism is simply outdated. Polygeneric hyperfunctions, compile-time compilation, self-destroying constructors, std::textstring and many other features essentially make C++63 a new language. We should call it Novel C++ to clearly distinguish it from C++5x.

byko3y ★★★★
()
Ответ на: комментарий от eao197

https://lesleylai.info/en/const-and-reference-member-variables/

Тот самый случай, когда «смотрю в книгу, вижу фигу».

Ты про это?

In some cases, you already disabled the assignment and move operations, or you need to write your own anyway. One of the primary examples is inheritance hierarchies. And in those cases, it is fine to use const or reference member variables.

Another use case of const or reference members is in local function objects, where you don't care about assignment behavior. For example, variables captured by reference in a lambda expression are desugared into reference member variables.

Я не вижу, как эти исключения применимы к твоему случаю.

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от byko3y

Дефайн, по крайней мере для примитивных типов, рождает такие же константы, как и constexpr.

Рождает значения, не константы.

И тут еще есть большой вопрос по типам, т.к.

#define MY_VAL 0x81

и

consexpr std::uint8_t my_val{ 0x81 };

имеют разные типы. Что может вести к серьезным последствиям.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

И тут еще есть большой вопрос по типам, т.к.
#define MY_VAL 0x81
и
consexpr std::uint8_t my_val{ 0x81 };
имеют разные типы. Что может вести к серьезным последствиям.

#define MY_VAL std::uint8_t(0x81)

Одинаковые.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Прежде всего вот об этом:

There are solid reasons on why you should avoid const or reference member variables in C++. Nevertheless, like many things in C++, «avoid» does not mean «never use.»

А так же следовало бы задуматься о том, что написано в самом-самом начале:

In the conventional wisdom of the C++ community, non-static const or reference data variables are considered problematic. Surprisingly, I cannot find a single resource dedicated to this topic.

О том, почему эта тема всего лишь «conventional wisdom». И почему на эту тему так мало говорят.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

О том, почему эта тема всего лишь «conventional wisdom». И почему на эту тему так мало говорят

Писать просто и понятно, так, чтобы 8-летний ребенок мог внести правки в твой код — это невостребовано, потому что это подразумевает отсутствие сложности. Коучи и авторы книг продают знания и приемы, которые трудно освоить, потому они топят за исключения и ссылки — чтобы потом можно было долго и прибыльно обучать правильно обрабатывать высвобождение объектов и инициализировать ссылки. Так-то это перегруженность фичами и подводными камнями — это общая болячка C++... за которую его и любят авторы книг.

byko3y ★★★★
()
Ответ на: комментарий от eao197

#define MY_VAL std::uint8_t(0x81)

Это не тот код, который я показывал.

И что? Это не код? То, что define может быть с типом и без типа — это внезапно его недостаток?

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Писать просто и понятно, так, чтобы 8-летний ребенок мог внести правки в твой код — это невостребовано, потому что это подразумевает отсутствие сложности.

Пилять.

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

Пилять два раза.

Так-то это перегруженность фичами и подводными камнями — это общая болячка C++… за которую его и любят авторы книг.

Да етить-же-ж-колотить.

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

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ну в STL по итогу сделали «через раз».

И?

И тогда мое утверждение остается в силе:

>const T & – это не гарантия иммутабельности объекта типа T, а всего лишь read-only view на объект типа T

Это работает только при условии, что «объект тип T» является тривиальным, у него нет динамического выделения ресурсов, ссылок, и прочих очень популярных среди кодеров на C/C++ штучек. Правда, в таких случаях зачастую можно просто копировать значение и не париться вообще, поскольку компилятор выоптимизирует копирование. Иначе получаем read-only view, через который можно изменить какую-то часть объекта, но не всегда, и прочие радости жизни, которые становится тем веселее, чем сложнее объекты.

Схерали? А мысль о том, что app_context_t изначально не предназначен для копирования, в голову не приходила?

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

А вот я утверждаю, что в моих сорцах везде const_cast будет использоваться только корректно, я его не буду использоваться в случаях, приводящих к UB.

Доказательства уровня «мамой клянусь», конечно же, имеют право на существование и даже широко используются при программировании на C++.
Но хорошего в этом нет

Суть была не в самом UB, а в том, что C++ позволяет делать очень много того, чего лучше в коде не делать. Но некоторые считают своим долгом задействовать каждую фичу крестов в своем коде. Эдакий «челлендж».

А я утверждаю, что проверка константности в C++ настолько дырява, настолько ненадежна, что по const-комментариям производится только крайне ограниченная проверка, без которой, в общем-то, можно жить

Без мозгов в голове тоже жить можно, но зачем?

А по сути возразить нечего? Ок.

byko3y ★★★★
()
Ответ на: комментарий от eao197

Прежде всего сделали работающий инструмент. А потом именно им повезло. … Рецепта достижения успеха нет. Но необходимая составляющая – это сделанный работающий инструмент, удобный хотя бы для своих создателей.

Я тоже так думаю.

бремя доказательства лежит на том, кто утверждение выдвинул

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

При этом я оставляю оппонентам доказать, что дело все-таки в их (т.к. byko3y и Kogrom) программисткой гениальности.

byko3y к этому идёт. Что касается меня, то я сделал «работающий инструмент, удобный хотя бы для своего создателя». Но я на гениальность не претендую. Кроме того, я то считаю, что Страуструп и Россум - гении. Однако, это не повод считать byko3y психом. Просто у него другое мнение.

Если вам что-то осталось непонятно, то скажите что именно, постараюсь объяснить подробнее.

Хорошо. Не буду разбирать конкретный код byko3y. Обсудим возможность декомпозиции любого кода на какой-нибудь простом наглядном примере. Допустим, у нас есть протокол, по которому одно устройство управляет другим. В протоколе есть 100 команд. Для обработки их можно использовать case, благодаря которому мы и получим большое количество строк кода. Как можно декомпозировать? Ну можно сделать map с указателями на функции. Но это не будет сильно лучше по читаемости, да ещё и внесёт задержки. Можно тупо разделить: если код команды меньше N, то обрабатываем одной функцией, если больше - то другой. Но это будет декомпозиция ради декомпозиции. Даже если мы разобьём команды на близкие по смыслу для разбора в разных функциях, то это ничего не добавит к читаемости. Всё равно обработку придётся искать по коду команды.

Kogrom
()
Ответ на: комментарий от eao197

Пусть меня забанят за грубость, но когда какой-то очень странный персонаж пытается подходить к решению технических проблем посредством маркетингового конспироложества, то единственное разумное, что можно сделать – это послать такого ыксперда в пешее эротическое

Ага, то есть, я угадал, и ты сам продаешь свои способности создавать и разбираться в зубодробильных конструкциях? Может быть я тебя удивлю, но со временем всё меньше работодателей готовы это покупать. Это произошло еще с лиспом, когда «творцов» распустили и на их место посадили питонистов.

byko3y ★★★★
()
Ответ на: комментарий от Kogrom

Ну так byko3y и доказывает, приводя новые и новые доводы.

Я так и не увидел доводов, которые бы позволили считать Страуструпа «манагером-продажником». Какой-то бред на заданную тему был, доводов не было.

byko3y к этому идёт.

Простите, к чему он идет?

Однако, это не повод считать byko3y психом.

Повод появляется из-за упорного нежелания byko3y принимать окружающую действительность.

Просто у него другое мнение.

Несовпадающее с реальностью.

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

Для разговора о читаемости нужно иметь код перед глазами.

Из личного опыта: большие по размеру функции – это всегда проблемы. Всегда. Причем проблемы, как правило, отложенные по времени. Тупо потому, что человек не способен удерживать в поле своего внимания большое количество деталей. А в длинной функции это количество будет чрезмерным.

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

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

Кроме подхода с map-ом может быть еще и подход на базе таблицы функций (собственно, тот же case, но записанный другим способом).

eao197 ★★★★★
()
Ответ на: комментарий от byko3y

Ага, то есть, я угадал

Нет.

ты сам продаешь свои способности создавать и разбираться в зубодробильных конструкциях?

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

eao197 ★★★★★
()
Ответ на: комментарий от byko3y

И тогда мое утверждение остается в силе:

Нет. Из того, что const T& – это лишь read-only view не следует тот поток бреда, который вы процитировали.

Это вообще все в очередной раз из категории «в огороде бузина…»

Не приходило.

Это может быть из-за того, что вы C++а толком не знаете и программируете на нем всего пару месяцев. Чтобы запретить копирование не обязательно вручную выписывать delete для конструкторов/операторов копирования.

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

Если такая простая структура вызывает у вас желание встать раком, то вам лучше сменить язык программирования. А лучше и профессию.

Но некоторые считают своим долгом задействовать каждую фичу крестов в своем коде.

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

А по сути возразить нечего?

Так сути-то нет, возражать не на что.

eao197 ★★★★★
()
Ответ на: комментарий от byko3y

То, что define может быть с типом и без типа — это внезапно его недостаток?

Это отличие от констант. Одно из.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от eao197

Тут дело в том, что мы в своей работе опираемся на абстракции, которые построены на других абстракциях. Соответственно, отрываемся от земли, образно говоря. Чтобы не потерять контроль над тем что происходит, полезно опускаться на землю, разбирать каждую абстракцию снизу вверх. byko3y своими вопросами и утверждениями (возможно, глупыми) даёт Вам это сделать в увлекательной форме.

Из личного опыта: большие по размеру функции – это всегда проблемы. Всегда.

Да. Это так. Но из этого не следует, что всегда есть альтернатива.

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

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

Kogrom
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.