Здравствуйте, B0FEE664, Вы писали:
S>>а можно пожалуйста пример чем соверменный С++ хуже Си в таких проектах BFE>Тут дело не в языке, а в бюрократии и особых требованиях. BFE>Например, в авионике это 100% покрытие кода тестами. BFE>В частности, если у вас есть вызов new, то надо предоставить тест, который обрабатывает исключение бросаемое new при нехватке памяти. И так для каждого встречающегося в коде new, а не в одном каком-то месте. Представляете себе объём работы по написанию тестов? Исходя из этого для многих проектов просто запрещается динамическая аллокация памяти. Соответственно выбрасывается всё, что аллоцирует память, начиная с std::vector ...
Глупости какие. Я например периодически пишу код для МК и использую там на полную удобства C++17 (скоро уже на 20 буду переползать). При этом там естественно нет динамического выделения памяти в принципе.
Здравствуйте, Ночной Смотрящий, Вы писали:
DI>>7-8 будет хайлоад, я там выступаю с докладом НС>Не нашел
Кстати, в контексте данной дискуссии довольно забавно, что там не мало докладов по C++ тематике. Я и не думал, что C++ имеет существенное распространение в данной области за пределами таких специфических монстриков как Гугл, Яндекс и т.п.
Здравствуйте, CreatorCray, Вы писали:
Pzz>>В комментарии к функции написать. CC>Бугага!!!
Давай я попробую вкратце изложить свою позицию.
Автоматизированные проверки сами по себе являются безусловным благом. Их достоинства прекрасно описаны миллионом других людей, и я не вижу смысла повторяться. При этом ценность статических проверок существенно выше, чем ценность проверок во время исполнения, потому что статические проверки действуют независимо от состояния программы, а чтобы сработала динамическая проверка, программу еще надо загнать в соответствующее состояние.
Однако за это благо мы платим определенную цену. Например, явно описываем типы данных, описываем свойства этих типов, описываем "контракты" между частями нашего кода. И чем более детальную мы хотим проверку, тем больше возрастает эта цена, причем начиная с какого-то момента она начинает расти непропорционально.
Отсутствие проверок тоже имеет свою цену. Например, больше шансов пропустить ошибку в продакшен, более внимательно приходится думать головой там, где компилятор мог бы поймать нас за руку и т.п.
Так вот, несмотря на то, что автоматизированные проверки являются безусловным благом, нет смысла платить за них большую цену, чем мы заплатили бы за их отсутствие. В какой-то момент надо остановиться, и сказать компилятору, "спасибо, но дальше я сам".
Pzz>> Я серьезно. CC>Сколько ты лет работаешь в команде?
Это совершенно не имеет отношения к обсуждаемой проблеме. Давай говорить по сути, а не обсуждать личности друг друга.
Здравствуйте, Marty, Вы писали:
M>Но вот например, забагованное до нельзя поделие — GCC — написано от и до на чистой сишечке, а качественный компилятор с человеческим лицом (clang/llvm) — на C++
Вообще то gcc уже давно перешли на C++. Ну и да, архитектурно clang конечно на порядки лучше. Только вот при этом он пока является худшим в производительности генерируемого кода среди всех основных компиляторов. Так что я конечно же надеюсь когда-нибудь полностью перейти на него (хороши когда сообщения об ошибках человеческие и всё такое), но до этого времени ещё очень далеко (им ещё работать и работать над оптимизатором).
Здравствуйте, so5team, Вы писали:
S>И это мы еще не рассматривали такие мощные инструменты для создания абстракций, как классы и шаблоны. Например, как вы в чистом C выразите абстракцию "значение в заданном диапазоне", которая на C++ делается влет простым шаблоном вроде:
Я что-то не понял, а операции + и — для этого constrained_value современный компилятор сам выведет, или их тоже надо руками расписать?
Здравствуйте, alex_public, Вы писали:
_>Глупости какие. Я например периодически пишу код для МК и использую там на полную удобства C++17 (скоро уже на 20 буду переползать). При этом там естественно нет динамического выделения памяти в принципе.
А что значит, нету в принципе? Ты не используешь слово new, или все твои алгоритмы имеют требования к памяти O(1)?
Здравствуйте, Pzz, Вы писали:
Pzz>А вот можно ли передавать NULL в качестве параметров, это маловажное знание. Потому что даже если я ошибусь в этом месте, то я быстро узнаю правду, и долгоиграющих последствий от такой ошибки не будет.
тут в ветке nekocoder уже жаловался на то что ссылку можно инициализировать nullptr.
если бы в параметрах приходящему объекту было прописано требование not_null, то и проблем с поиском бага бы не возникло.
Здравствуйте, Pzz, Вы писали:
S>>И это мы еще не рассматривали такие мощные инструменты для создания абстракций, как классы и шаблоны. Например, как вы в чистом C выразите абстракцию "значение в заданном диапазоне", которая на C++ делается влет простым шаблоном вроде:
Pzz>Я что-то не понял, а операции + и — для этого constrained_value современный компилятор сам выведет, или их тоже надо руками расписать?
В том-то и дело, что для простейшего случая это и не нужно. В нем есть операция приведения к типу T, поэтому показанный тривиальный constrained_value можно использовать вот так, например:
my_range get_current_value() {
my_range raw = read_raw_value(); // Гарантия того, что в raw допустимое значение.short tmp = static_cast<short>(raw) * 10; // Вот тут все гарантии потерялись.if(specific_moon_phase())
tmp += 135;
if(some_time_of_day())
tmp /= 3;
return my_range{tmp}; // Здесь появляется гарантия того, что возвращается допустимое значение.
}
Здравствуйте, so5team, Вы писали:
S>В том-то и дело, что для простейшего случая это и не нужно. В нем есть операция приведения к типу T, поэтому показанный тривиальный constrained_value можно использовать вот так, например:
Мне этот код не нравится. Не нравится он мне тем, что из него может прилететь исключение. Причем в этом исключении будет сказано лишь, что оно относится к некоему constrained_value.
Т.е., если мы выносим такую функцию в интерфейс, скажем, класса, который читает конфигурацию, то тот, кто использует этот класс, должен быть готов, что к нему прилетят исключения, не имеющие в себе никакой информации ни о конфигурационном файле, ни о том, как найти и исправить возникшие проблемы, но зато ссылающиеся на некие низкоуровневые типы, которые читалка конфигирации удосужилась использовать на данном этапе своего развития. Потому что в конечном итоге пользователю надо показать не стек вызовов, а что-нибудь типа "чувак, у тебя в файле myconfig.cfg в 35-й строке какая-то хрень написана, исправь пожалуйста"). И кто-то в пути должен это уметь делать. Причем желательно бы кто-то, кто понимает про конфигурационные файлы, а не тот, кому эти значения на пять этажей выше нужны для работы, и кому все равно, откуда они взялись, лишь бы они были правильными.
S>Теперь хотелось бы посмотреть на это в чистом С.
В C я написал бы явную проверку. И вернул бы явную ошибку. А в Go еще удобнее, я вернул бы результат и ошибку одним махом, там функция может вернуть сразу несколько значений.
Здравствуйте, Pzz, Вы писали:
S>>В том-то и дело, что для простейшего случая это и не нужно. В нем есть операция приведения к типу T, поэтому показанный тривиальный constrained_value можно использовать вот так, например:
Pzz>Мне этот код не нравится. Не нравится он мне тем, что из него может прилететь исключение. Причем в этом исключении будет сказано лишь, что оно относится к некоему constrained_value.
Вас куда-то постоянно уносит в сторону. И, складывается ощущение, что это от незнания инструмента о котором вы пытаетесь судить. А может и от специфического опыта.
Суть constrained_value в том, чтобы содержать заведомо корректное значение. Ответственность за получение этого значения лежит на разработчике. Соответственно, прежде чем поместить что-то в constrained_value вы можете сделать столько проверок, сколько вам нужно. И проинформировать о проблемах так, как вам хочется. Но, если вы этого по каким-то причинам не сделали, то constrained_value не позволит вам вернуть заведомо некорректное значение. И тот, кто ждет от вас constrained_value, может быть в этом уверен.
S>>Теперь хотелось бы посмотреть на это в чистом С.
Pzz>В C я написал бы явную проверку.
И после этого вы еще чего-то говорите про человеческий фактор и его влияние?
Pzz>И вернул бы явную ошибку. А в Go еще удобнее, я вернул бы результат и ошибку одним махом, там функция может вернуть сразу несколько значений.
Рискую вас удивить, но в C++ вы запросто можете вернуть, скажем expected, которое будет содержать либо нормальный результат, либо ошибку. Что сильно лучше, чем два значения в Go, одно из которых заведомо некорректно.
Здравствуйте, so5team, Вы писали:
Pzz>>Мне этот код не нравится. Не нравится он мне тем, что из него может прилететь исключение. Причем в этом исключении будет сказано лишь, что оно относится к некоему constrained_value.
S>Вас куда-то постоянно уносит в сторону. И, складывается ощущение, что это от незнания инструмента о котором вы пытаетесь судить. А может и от специфического опыта.
Нет, не уносит. В программировании, за пределами школьного курса, нет такой задачи "прочитать откуда-нибудь какое-нибудь значение, и дать гарантии, что оно попадает в диапазон". Есть задачи прочитать значение из файла, ввести его от пользователя, получить по сети и т.п., и осмысленная обработка ошибок занимает больше кода, чем собственно получение значения.
Говорить об инструменте имеет смысл в контексте решения практических, а не школьных, задач. Если довести ваш пример до нормального состояния, что там был ваш constrained_value, что его не было, разница будет не шибко заметна.
S>Суть constrained_value в том, чтобы содержать заведомо корректное значение. Ответственность за получение этого значения лежит на разработчике. Соответственно, прежде чем поместить что-то в constrained_value вы можете сделать столько проверок, сколько вам нужно. И проинформировать о проблемах так, как вам хочется. Но, если вы этого по каким-то причинам не сделали, то constrained_value не позволит вам вернуть заведомо некорректное значение. И тот, кто ждет от вас constrained_value, может быть в этом уверен.
Я, вообще-то, не хочу иметь в программе переменную, которая выглядит как целочисленная, только не позволяет складывать, при каждом присваивании делает пару проверок и иногда плюется исключениями. Это совершенно вредная штука, пусть даже C++ и позволяет создавать их с легкостью.
Pzz>>В C я написал бы явную проверку.
S>И после этого вы еще чего-то говорите про человеческий фактор и его влияние?
Говорю, да. В программе на C++, скорее всего, ничего, кроме проверки, встроенной в constrained_value, и не будет. И исключение никто не будет обрабатывать до самого верха. А наверху приделают кнопочку "ой, программа упала, послать дамп разработчикам?". Таков он, человеческий фактор.
S>Рискую вас удивить, но в C++ вы запросто можете вернуть, скажем expected, которое будет содержать либо нормальный результат, либо ошибку. Что сильно лучше, чем два значения в Go, одно из которых заведомо некорректно.
Угу. А потом мы начинаем сводить в одном проекте 5 библиотек, каждая из которых содержит свою реализацию expected, совершенно идентичную 4-м остальным, но формально несовместимую с ними, потому что разные типы.
Здравствуйте, alex_public, Вы писали:
_>Тебе приходится много лет возиться с тоннами legacy кода? Даже не могу выразить всю степень своего сочувствия... Наверное на такое могут сподвигнуть только очень тяжёлые жизненные обстоятельства...
Хорошо вам там в альтернативной вселенной, где проекты сразу после завершения выбрасываются и переписываются с нуля.
Здравствуйте, Pzz, Вы писали:
_>>Глупости какие. Я например периодически пишу код для МК и использую там на полную удобства C++17 (скоро уже на 20 буду переползать). При этом там естественно нет динамического выделения памяти в принципе.
Pzz>А что значит, нету в принципе? Ты не используешь слово new,
Все "выделения" памяти в проекте делятся на 3 части: глобальные переменные, статические переменные (по сути те же глобальные, только с ограниченной областью видимости), переменные на стеке. Динамической кучи нет в принципе, как явления (да и куда её там размещать в 16 Кб оперативки, в которых при этом ещё и стек должен помещаться?).
Pzz>или все твои алгоритмы имеют требования к памяти O(1)?
Скажем так: в данной области почти всегда алгоритмы подгоняют под железо, а не наоборот.
Здравствуйте, Pzz, Вы писали:
Pzz>В C я написал бы явную проверку. И вернул бы явную ошибку. А в Go еще удобнее, я вернул бы результат и ошибку одним махом, там функция может вернуть сразу несколько значений.
Ну это уже совсем незнание темы... В C++ давным давно можно было возвращать несколько значений с помощью кортежей. А в последнем стандарте ещё и добавили к этому максимальный сахар (https://en.cppreference.com/w/cpp/language/structured_binding), чтобы стало уж совсем удобно (как в Питоне и тому подобных языках).
Здравствуйте, nekocoder, Вы писали:
_>>Тебе приходится много лет возиться с тоннами legacy кода? Даже не могу выразить всю степень своего сочувствия... Наверное на такое могут сподвигнуть только очень тяжёлые жизненные обстоятельства... N>Хорошо вам там в альтернативной вселенной, где проекты сразу после завершения выбрасываются и переписываются с нуля.
Ээээ, что? С чего бы это мой текущий проект (написанный на C++17) после своего релиза вдруг резко станет legacy? Ну т.е. конечно же лет через 10-15 (если проект просуществует всё это время) он возможно и станет таковым, но я им точно уже заниматься не буду (на самом деле я им уже и через год заниматься не буду, но это к делу не относится — будут заниматься сотрудники и для них он всё равно очевидно не будет legacy).
Здравствуйте, alex_public, Вы писали:
_>Ну это уже совсем незнание темы... В C++ давным давно можно было возвращать несколько значений с помощью кортежей. А в последнем стандарте ещё и добавили к этому максимальный сахар (https://en.cppreference.com/w/cpp/language/structured_binding), чтобы стало уж совсем удобно (как в Питоне и тому подобных языках).
Я знаю про тупли. Но тупли — это не то же самое, что возврат нескольких значений.
Здравствуйте, Pzz, Вы писали:
Pzz>Есть задачи прочитать значение из файла, ввести его от пользователя, получить по сети и т.п., и осмысленная обработка ошибок занимает больше кода, чем собственно получение значения.
Вы умалчиваете о том, что задача "прочитать значение из файла, ввести его от пользователя, получить по сети и т.п." не определяет детали реализации. А в этих деталях будет скрываться то, сколько ошибок вы допустите вручную проверяя все и вся. Как раз возможность реализации типов, подобных constrained_value, вносит дополнительную степень защиты и явно определенные контракты. Вы из кода будете видеть, что отсюда читается значение в таких-то единицах, затем преобразуется в такое-то значение из такого-то диапазона и приходит к передаче в сеть строго вот таком-то виде.
Вы все это сможете увидеть в типах и компилятор с run-time будет бить вам по рукам за каждый шаг в сторону. Это сильно лучше, чем обычные int-ы или float-ы с комментариями вокруг них.
Pzz>Говорить об инструменте имеет смысл в контексте решения практических, а не школьных, задач.
Так вы же не можете в примеры. Ну вот совсем. Ваш максимум -- это сравнение с презервативами. Ничего предметного в обсуждении от вас не было. Ну, кроме демонстрации незнания C++.
Pzz>Если довести ваш пример до нормального состояния, что там был ваш constrained_value, что его не было, разница будет не шибко заметна.
Давайте сначала увидим ваш вариант этого constrained_value на чистом C. После чего можно будет, если будет возможность, поговорить и о том, чего вы в наличии и использовании constrained_value в упор не понимаете.
Pzz>Я, вообще-то, не хочу иметь в программе переменную, которая выглядит как целочисленная,
Так она и не выглядит как целочисленная. Она выглядит как жесткий контейнер для одного значения.
Pzz>Говорю, да. В программе на C++, скорее всего, ничего, кроме проверки, встроенной в constrained_value, и не будет. И исключение никто не будет обрабатывать до самого верха. А наверху приделают кнопочку "ой, программа упала, послать дамп разработчикам?". Таков он, человеческий фактор.
Давайте назовем вещи своими именами: в вашей программе на C++, скорее всего, ничего, кроме проверки, встроенной в constrained_value, и не будет. И исключение вы не будете обрабатывать до самого верха.
Так оно всяко объективнее получится.
Pzz>Угу. А потом мы начинаем сводить в одном проекте 5 библиотек, каждая из которых содержит свою реализацию expected, совершенно идентичную 4-м остальным, но формально несовместимую с ними, потому что разные типы.
Вообще-то не зря была дана ссылка на expected, поскольку это уже доступная сейчас реализация того, что будет в C++20.
Но даже такой зоопарк будет сильно лучше, чем обычный int в чистом C, который будет гулять между модулями вообще без какой-либо сопроводительной информации.
Здравствуйте, alex_public, Вы писали:
_>Скажем так: в данной области почти всегда алгоритмы подгоняют под железо, а не наоборот.
У меня был проектик, в котором памяти было 128 байт. Причем мне сначала наврали, что их 256, а я сдуру и не проверил. А потом стек сделал wrap around, и пришлось импровизировать на ходу
Здравствуйте, Pzz, Вы писали:
_>>Ну это уже совсем незнание темы... В C++ давным давно можно было возвращать несколько значений с помощью кортежей. А в последнем стандарте ещё и добавили к этому максимальный сахар (https://en.cppreference.com/w/cpp/language/structured_binding), чтобы стало уж совсем удобно (как в Питоне и тому подобных языках). Pzz>Я знаю про тупли. Но тупли — это не то же самое, что возврат нескольких значений.
Вообще то в большинстве языков оно как раз через кортежи и работает (например Питон):