LINUX.ORG.RU

юнионы в C++

 


2

4

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

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

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

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

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

★★★★★

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

Не, мне-то всего хватает. Я имею в виду, они нужны по мере поступления. Когда математики родили новый алгоритм, или гугло вывалило какой-нибудь хттп100500, или ты вот принципиально новую БД написал.
А айтишку уничтожают и без тебя, только с другой стороны. Будет как с другими областями: когда-то портной, мельник, кузнец были уважаемыми и талантливыми людьми, при клиентах и бабосах. Сейчас они где?
Так будет и с программистами. Тринадцатилетние дети в бангладеше и пакистане (и у нас) будут лепить вебню за полчаса от получения ТЗ, по 12 часов в день, чтобы было чем наутро позавтракать. И уже лепят, и не только на вордпрессе, за пять баксов в час. Там, я думаю, за тот же прайс предлагаются и нейросети и блокчейн и глушитель приварить и котенка утопить.

Да чего я, это всем уже давно очевидно.

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

когда то пытался сделать универсальную генерилку плюсового кода на питоне, не вышло по ряду причин.

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

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

лисп отличается от сей и иже с ними прежде всего тем, что ты не пересоздаёшь Вселенную заново, когда тебе надо перенести стул из одной комнаты в другую. Замена С++ на D или Rust именно на это обстоятельство никак не повлияет.

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

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

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

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

Люди всегда были не нужны. Но это никому никогда не мешало.

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

Так Tiobe же вроде меряет количество публикаций в сети. Конечно, про C++ можно писать бесконечно - вот вы тут на 15 моих страниц нафлудили про один только const. А голанг - язык простой, видимо, уже нечего в нём обсуждать, всё написали и дальше писать нечего. Но ок, я понял, откуда мнение. Я предпочитаю мерять по количеству вакансий на hh.ru - индекс, который мне лично ближе к телу (и моего ранее любимого Common Lisp по этому индексу вообще практически не существует). А что именно усложнили? Они впилили дженерики?

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

компилятор это просто игнорирует.

Но плохо что по этому поводу нет предупреждений ни в gcc, ни в clang, ни в Visual C++ :(

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

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

Виртуальный же метод можно, а это тоже не ООП (в смысле Лисковой). ООП в плюсах - это не ООП, а некое такое месиво из абстракции и хаков для ужатия кода. Это можно было бы тоже вписать в недостатки, но это слишком сложно для большинства. Сразу пример: http://citforum.ru/programming/digest/lspv/

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

Виртуальный же метод можно, а это тоже не ООП (в смысле Лисковой)

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

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

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

Я вообще не люблю ООП ни в каком виде. Годы назад я пытался писать, в т.ч. и тут, что если взять SQL + язык а-ля PL/SQL, то мы видим абстракции, модель работы с параллельностью (даже обработка дедлоков), компилятор, который оптимизирует запросы, декларативный язык. Т.е. за тебя делают много сложной работы. Если же возьмём ООП в любом виде, то это не более чем дисциплина, которая якобы чему-то там помогает в организации (что само по себе уже спорно - не факт, что в конкретных популярных вариантах ООП больше помогает, чем мешает). Никакой работы, которую бы компьютер делал за человека, мы тут не наблюдаем. Поэтому реляционная парадигма - это круть, а ООП - так себе. Понятно, что никто меня не слушал, да и ладно. Теперь мне уже не важно кого-то в чём-то таком убеждать. Если мы ставим перед собой стратегическую задачу отсрочить победу компьютера над человеком, то нужно радоваться, что у нас есть С++ и Си - оба языка хорошо подходят, и кроме того, в какой-то степени уравнивают сильных и слабых, т.к. на них хорошо писать программы с дырами.

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

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

Я вообще не знал что так можно до твоего коммента :)

сейчас в godbolt поигрался и узнал что до гцц 4.7 это не работало.

Видимо добавили, чтобы можно было наследоваться от тайпдефов с const.

https://gcc.godbolt.org/z/xcfG4Y5PW

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

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

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

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

Годы назад я пытался писать, в т.ч. и тут, что если взять SQL + язык а-ля PL/SQL, то мы видим абстракции, модель работы с параллельностью (даже обработка дедлоков), компилятор, который оптимизирует запросы, декларативный язык. Т.е. за тебя делают много сложной работы. Если же возьмём ООП в любом виде, то это не более чем дисциплина, которая якобы чему-то там помогает в организации (что само по себе уже спорно - не факт, что в конкретных популярных вариантах ООП больше помогает, чем мешает). Никакой работы, которую бы компьютер делал за человека, мы тут не наблюдаем. Поэтому реляционная парадигма - это круть, а ООП - так себе.

C# LINQ вроде попытка сделать нормально, но я сам не пользовался

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

На самом деле, если подумать, цель моих инициатив — это уничтожить IT. Внезапно. Сделать так, чтобы индусы отправились мести двор, а в индустрии осталось три целых семь десятых программиста.

И ты надеешься попасть число оставшихся?..

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

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

Это что ли про ансейф? Оставим пока в стороне «независимость» этих «подъязыков» (с чем я не согласен), но как бы ты сделал? Выкинул бы ансейф? Такой раст был бы мало кому нужен - тогда уж имело бы смысл добавить/оставить GC. Заморочек стало бы меньше, но это был бы совершенно другой язык. Оставить только ансейф (убрать гарантии от компилятора и пусть за всё отвечает программист)? Тоже такое себе.

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

На самом деле, если подумать, цель моих инициатив — это уничтожить IT. Внезапно. Сделать так, чтобы индусы отправились мести двор, а в индустрии осталось три целых семь десятых программиста.

Хм, а зачем? Тебе нравится мести двор или ты посчитал, что твой шанс примерно в 1 пятимиллионную попасть в три целых семь десятых тебя устроит?

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

медленная компиляция;

согласен, это недостаток

переусложненность как минимум двумя независимыми подъязыками (по аналогии с C и C++);

unsafe понял (он необходим для портирования программ с иных языков), а второй?

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

Так ты ж говорил, что const слишком простой и поэтому неадекватен. Ты предлагал его вообще убрать? Или дорастить до сложности, при которой он уже станет адекватен? Или ты не то говорил?

то есть, ты большую часть времени будешь читать вспомогательные конструкции, а не логику.

Ну здесь всего два варианта: либо ты хочешь контролировать в программе всё, а она, сцуко, сложная штука. И тогда да, большую часть времени будешь читать вспомогательные конструкции. Либо же делегируешь компьютеру право контролировать что-то за себя, тогда программа проще и читать меньше, но и возможностей повлиять на поведение меньше.

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

unsafe понял (он необходим для портирования программ с иных языков)

Не только.

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

Я вообще не знал что так можно до твоего коммента :)

сдается мне, что плюсовики перемудрили с const. по моему это не должно быть квалификатором типа, а должно быть квалификатором обьекта. то есть например строка не есть обьект класса «константная строка», а константый обьект класса строка.

константных типов, короче, быть вообще не должно.

то есть запись

typedef const Type ConstType;

должна быть некорректна

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

сдается мне, что плюсовики перемудрили с const … должна быть некорректна

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

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

Из stl:

      typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
      typedef __gnu_cxx::__normal_iterator<const_pointer, vector>
      const_iterator;

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

я даже никогда не думал, что мне такое надо,

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

тогда в первом случае я наследую констатный вариант класса.

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

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

странно это всё, тут ведь будет отламываться дефолтная стратегия копирования (ctr, =). Я константных полей/базовых классов вовсе не использую (неконстантный указатель на константу - это другое).

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

const class - это сущность из той же серии, что struct (типа public class), enum class и пр.

В терминологии python такие штуки - это метаклассы, в терминологии C++ - подозреваю, что концепты

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

подозреваю, что концепты

enum class - это просто такой более человечный(типа обычный для других языков) enum, который скрывает элементы внутри себя и к ним надо доступаться с именем перечисления.

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

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

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

По-моему это логично. Ты не «снял константность класса». Ты хочешь порождать объекты нового типа CDerived, который не объявлен константным, и который содержит поля, не объявленные константными. Ну вот и пожалуйста.

Но ворнинг здесь бы не помешал.

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

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

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

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

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

Это называется «горе от ума».

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

Не содержит.

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

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

физически он содержит НЕКОНСТАНТНЫЕ поля предка, константность которого никого не волнует, потому что самого предка здесь нет.

Вот видишь, как важно, каким глаголом это описывается. Не надо смешивать generalization и composition.

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

физически он содержит НЕКОНСТАНТНЫЕ поля предка,

что в лоб, что по лбу. еще раз вопрос - почему поля константного класса(!) стали волшебным образом неконстантными для внешнего мира. Зачем его вообще таковым обьявляли, если это обьявление можно игнорировать простым трюком?

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

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

Зачем его вообще таковым обьявляли

я не знаю. Кстати, я полностью согласен с твоим мнением насчет разумности запрета typedef const ClassName.

Зачем его вообще таковым обьявляли, если это обьявление можно игнорировать простым трюком?

Ты ничего не игнорировал. Агрегируй объект константного типа и наслаждайся.

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

Если в ЯП есть кастование указателей, то ты уже автоматически получаешь union, только неформальный.

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

Tagged Union/Algebraic Data Type нужны именно для того, чтобы компилятор мог гарантировать корректность доступа.

101 раз: ты неявно предполагаешь, что пишется большая программа, которой, в общем-то, наплевать на аппаратуру. А это не всегда так. Поэтому нужны и надёжные инструменты, и простые с минимальными накладными. Как их разделять, другой вопрос. да хоть через @safe / @system, как в D. Главное, чтобы они были в ассортименте.

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

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

Боюсь промазать, но с const разве не так же? С одной стороны это слово означает неизменный объект, а с другой - оно же означает объект, доступный только для чтения. Не?

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

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

Это называется «горе от ума».

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

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

Был предок юникса, Multics, была еще ось от DEC, был VMS, совместимый с осью DEC. Собственно, на базе VMS создана винда NT, и она прекрасно переносилась меж компами. А вот Unix на то время вполне себе был приколочен гвоздями к одной архитектуре — портировался почти полностью ручками.

Могу только повториться, историю надо знать. Мультикс никогда так и не пошёл в серию. ось от DEC — это мониторы RSX? VMS, NT… смешались в кучу кони… Начать с того, что ты допускаешь анахронизм, указанные ОС разрабатывались в существенно разное время и занимали разные участки рынка. Нет уж, надо вспомнить, в начале 80-ых было даже не два, три сегмента: 1) мэйнфреймы 2) малые машины 3) микромашины, причём 2 и 3 начали сливаться вплоть до неразличимости. Соответственно, если не брать 1), на «рынке» безраздельно царили RSX, который стремились заменить на более гибкий UNIX и CP/M. VMS разрабатывалась позже, работала на дорогом оборудовании и никогда не была массовой.

Поэтому и в народ пошёл. И позднее вытеснил (более, чем популярные в то время) варианты Паскаля и бодро вытеснял Фортран

Фортран и Паскаль на то время сидели в совершенно разных нишах, это как говорить, что Rust вытесняет JavaScript. В одной нише с фортраном и паскалем были C++ и Basic

Соответственно, языки программирования несли в себе отпечаток доступных возможностей тогдашних систем. А когда начал развиваться массовый рынок «персоналок» (причём, ещё до IBM!), массовость попросту стала задавать тон. Какая ниша C++? Задолго до C++ мини и микромашинах задавали тон Бэйсик, Паскаль (гугл: Apple Pascal) и как ни странно, некоторое время пытался закрепиться Фортран, но не очень удачно. Бэйсик оставим отдельно, паскаль имел кучу ограничений и к тому-же, компилировал в тот-же Пи-код. Так что Си идеально пришёлся ко двору, тем более, что его конструкции идеально ложились на команды PDP и очень хорошо на 8080/8086.

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

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

Да, в самом нет PL/M структур/массивов, но их можно было реализовать на препроцессоре

Ой. даже без комментариев.

Вот никто же не заставлял K&R делать функции без прототипов, да?

Заставлял. Та же причина, из которой ноги растут у позиционности Фортрана и известных фич Бэйсика: скудость ресурсов.

Просто скажи мне, что заставило не иметь в C++ поддержки норм строк?

А что такое «нормальные» строки? Со счётчиком?

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

Проще верблюду пролезть сквозь игольное ушко, чем программисту попасть в царствие плюсовое.

8063 открытых бага https://github.com/rust-lang/rust/issues

(при том это только фронтэнд, проблемы бекэнда находятся тут https://github.com/llvm/llvm-project/issues)

7536 открытых https://github.com/golang/go/issues

В безопасных простых языках полно проблем, точно также как и в С++.

И рассуждать можно точно также как и про С++.

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

Точно также и в Javascript.

Тех кто читал стандарт Ecmascript единицы, также как и тех кто может различить баг хрома, баг firefox или ошибки в стандарте Javascript.

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

Знаешь, на каких высокоуровневых языках нынче пишут под микроконтроллеры с дюжиной кб оперативы? Си, Паскаль, Standard ML — во порядке убывания популярности. Близость к железу совершенно ортогональна наличию массивов.

Нет, не ортогональна : опять исторический контекст. Си работал(!) на машине с 32Кб ОЗУ и генерировал код, который на этой-же машине можно было исполнить. Понятно, что оптимизаций в этом случае было ровно ноль.

Это сейчас для контроллеров «с дюжиной кб» можно писать на ++, которые работают на машине с безразмерной памятью и могут себе позволить любые оптимизации. А в те времена классическое *(x++) = … было верхом изящества.

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

Вот зачем так портить настроение после обеда? Впрочем, я-то за Оберон, а он простой. Хотя в нём багов мало не потому, что их нет, а потому что он никому не нужен.

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

Нет, не ортогональна : опять исторический контекст. Си работал(!) на машине с 32Кб ОЗУ и генерировал код, который на этой-же машине можно было исполнить.

А Паскаль не работал?

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

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

потому, что примитивная донельзя и непосредственно «ложится» на модель памяти в виде последовательных ячеек. Потому, то равенство a[0] и *a позволяет передавать массив в любую функцию без накладных и бежать по массиву парой команд ассемблера.

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

А Паскаль не работал?

работал, ценой комиляции в Пи-код. Сильно быстрее Бэйска, но примерно на порядок медленнее Си.

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

Вот в D пришла авторам блажь перенести битовые поля на уровень библиотеки. Кому-то стало от этого хорошо?

А кому плохо?

допустим, мне. а что? 😎

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