LINUX.ORG.RU

Дискуссия об использовании языка C++ для разработки ядра Linux

 ,


1

5

В списке рассылки разработчиков ядра Linux возобновилось начатое шесть лет назад обсуждение перспектив использования современного кода на C++ в ядре Linux, помимо нынешнего применения языка Си с ассемблерными вставками и продвижения языка Rust. Изначально тема разработки ядра на C++ была поднята в 2018 году инженером из Red Hat, который первого апреля в качестве шутки опубликовал набор из 45 патчей для использования шаблонов, наследуемых классов и перегрузки функций C++ в коде ядра.

С инициативой продолжения обсуждения выступил Ганс Питер Анвин (Hans Peter Anvin), один из ключевых разработчиков ядра в компании Intel и создатель таких проектов как syslinux, klibc и LANANA, разработавший для ядра Linux систему автомонтирования, реализацию RAID 6, драйвер CPUID и x32 ABI. По мнению Анвина, который является автором многочисленных макросов и ассемблерных вставок в ядре, с 1999 года языки C и C++ значительно продвинулись вперёд в своём развитии и язык C++ стал лучше, чем С, подходить для разработки ядра операционных систем.

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

Анвин считает, что C++ более предпочтителен, чем Rust, так как последний существенно отличается от языка С по синтаксису, непривычен для текущих разработчиков ядра и не позволяет постепенно переписывать код (в случае языка С++ можно по частям переводить код с языка C, так как С-код можно компилировать как C++). В поддержку использования С++ в ядре также выступили Иржи Слаби (Jiri Slaby) из компании SUSE и Дэвид Хауэллс (David Howells) из Red Hat.

>>> Подробности

★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 1)

Ответ на: комментарий от kvpfs_2

Исключения сами начинают проситься

Да, исключения в этом случае не нужны. Отключить часть приложения без них – что может быть проще.

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

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

Создать ресурс где-то в произвольной точке функции и гарантированно его освободить, без возни с goto final и ручной очистки и без нестандартных расширений - это не нужен? Ты из свято верующих в собственную непогрешимость?

Моя непогрешимость отношения к делу не имеет. Речь о пользе голых unique_ptr. Они по сути позволяют запилить аналог джавовсого try with resources или шарпового using. Однако если я приду к фанатам плюсов и заявлю им, что их RIIA фигня, в джаве есть try with resources и он не хуже, то меня вполне справедливо обсмеют, так как try with resources эмулирует самый простой и самый бесполезный юзкейс RIIA. Ты же теперь говоришь что вот этот самый простой юзкейс ценен сам по себе.

Но и это ещё не всё, если я пишу

{
    auto ptr = std::make_unique<Foo>();
    ptr->bar(create_context());
}

(или аналог на других языках, с using или try) то главная фишка не в том что мне лень писать удаление, а в том, что create_context() может кинуть исключение и поэтому мне нужен надёжный автоматический вызов освобождения, даже в случае неочевидного перехода. Но в ведре чёткая политика: никаких исключений, соответственно подобный код ещё бесполезнее чем в плюсовом проекте.

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

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

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

п.с. все имхо, все через свой личный опыт

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

исключения в этом случае не нужны. Отключить часть приложения без них – что может быть проще.

Ну вот имеем некоторый модуль, который глубоко в своем ливере родил критическую ошибку. Для его отключения, эту инфу нужно поднять в основной модуль, который управляет всеми остальными. А ещё нам хочется знать причину. Вот начнется здесь протаскивание по стеку вызовов кучи служебной информации, бесконечная проверка состояния аля if (error) return error; это больно, засоряет код, теряется лаконичность.

Ещё stacktrace на подходе, если это будет не накладно (думаю, что не должно), то через исключения будет удобно и полезно протаскивать его выхлоп.

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

это только первый раз неудобство вызывает :о)

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

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

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

но теоретически в бинаре вся инфа должна быть по идее - таблица символов ведь имеется

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

А, может ты про ELF-ную таблицу символов… Хз, мозги не варят, но по интуитивным ощущениям – вряд ли. Там же только экспортируемые символы.

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

эмулирует самый простой и самый бесполезный юзкейс RIIA. Ты же теперь говоришь что вот этот самый простой юзкейс ценен сам по себе.

То, что это самый простой случай никак не отменяет того, что сам по себе он ценен и полезен.

то главная фишка не в том что мне лень писать удаление, а в том, что create_context() может кинуть исключение и поэтому мне нужен надёжный автоматический вызов освобождения

Я же не спорю. Это действительно хорошее свойство исключений + RAII. Но без исключений RAII не становится бесполезным. Просто пример становится многословнее:

{
    auto ptr = std::make_unique<Foo>();
    if (auto ctx = create_context(); ctx) {
        ptr->bar(ctx);
    }
    else {
        return get_error();
    }
}

Но это не про то, что RAII вдруг стал бесполезен, это про то, что исключения запретили и нужно обрабатывать ошибки явно.

тогда деструкторы потеряют почти все свои полезные свойства и это будут такие вот «плюсы для галочки»

Да все полезные свойства деструкторов на месте, никуда не делись. Просто на фоне явной обработки ошибок теряется локаничность кода, но это ведь не проблема RAII, а проблема отсутствия исключений.

а затем продолжать ныть на предмет «а давайте ещё вот это разрешим»

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

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

Да, про ELF. Я для теста написал:

#include <iostream>
extern "C" void fnqwerty() {std::cout << "hello";}
int main() {fnqwerty();}

Скомпилил на -O3, без всяких там -rdynamic, имя fnqwerty было в .symtab таблице. В общем инфы в ELF и так с головой хватает.

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

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

имя fnqwerty было в .symtab таблице

А если без extern? Впрочем, вспомнил: туда много лишнего попадало и без extern. Не помню по какому принципу, но мне пришлось передавать export-map в gcc, чтобы порезать всё лишнее, ибо нефиг подглядывать в мои потроха.

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

Если нужно просто прикрыть какой-то там модуль – это одно. А обработка ошибок через исклчюения – другое, когда в коде всюду try {} catch. Разные сценарии. Я не против описанного Вами сценария.

thegoldone
()

Раст засунули а про кресты еще колеблются. А может лучше наобот было?

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

в случае компилоятора это действительно проблема т.к бутстрап. В случае с ядром - нет.

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

достаточно заинлайнить конструктор, что при маленьком конструкторе произойдёт почти всегда при -O1 и выше. Ну и оператор bool, который позволит проверить что объект действительно создался. Для репорта кода ошибки можно использовать всё тот же глобальный errno как в си, а можно сделать метод в объекте (по идее вместо operator bool метод getError который проверяем на no_error)

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

Ну вот имеем некоторый модуль, который глубоко в своем ливере родил критическую ошибку. Для его отключения, эту инфу нужно поднять в основной модуль, который управляет всеми остальными. А ещё нам хочется знать причину. Вот начнется здесь протаскивание по стеку вызовов кучи служебной информации, бесконечная проверка состояния аля if (error) return error; это больно, засоряет код, теряется лаконичность.

дак надо как растоманы поступать. Фигачить бесконечные Result<T, E>, а там где их слишком много, фигачить unwrap(), кидать панику и заявлять что это не исключение, а совсем другое. Получающиеся CVE по-тихому исправлять, при этом громко рассказывать, какая у нас хорошая и современная обработка ошибок :)))

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

А теперь подумайте, как реализовать range-based for и как какой-нибудь BOOST_FOREACH.

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

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

Если использовать голову

Начинайте! Желательно с чтения документации, как там насчет Вашего утверждения что дескать «в библиотеках ничего нового не будет»?

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

Особенно для сложных контейнеров, да-да.

Foreach это просто синтаксический сахар, как и auto - но они делают код значительно более простым и читаемым.

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

Рад за вас.

Спасибо!
Я тоже рад!

500 строк потому, что используются в run-time метаданные (2600 строк) для конфигураций 1С 7.7


...
Последние строки в файле, содержащем метаданные конфигурации.

// -------------------------------------------------------
//
typedef struct MainMetaDataStream__ {

 MainDataContDef_             MainDataContDef;
 TaskItem_                    TaskItem;
 vector< GenJrnlFldDef_    >  GenJrnlFldDef;
 vector< DocSelRefObj_     >  DocSelRefObj;
 vector< HeaderDocNumDef_  >  DocNumDef;
 vector< Consts_           >  Consts;
 vector< SbCnts_           >  SbCnts;
 vector< Registers_        >  Registers;
 vector< Documents_        >  Documents;
 vector< Journalisters_    >  Journalisters;
 vector< EnumList_         >  EnumList;
 vector< Report_           >  ReportList;
 vector< CJ_               >  CJ;
 Calendars_                   Calendars;
 vector< HeaderAlgorithms_ >  Algorithms;
 vector< RecalcRules_      >  RecalcRules;
 vector< CalcVars_         >  CalcVars;
 vector< Groups_           >  Groups;
 vector< DocumentStreams_  >  DocumentStreams;
 MetaBuh_                     Buh;

} MainMetaDataStream_;

vector<> никакого отношения к C++ не имеет.
Это один из контейнеров, используемых в run-time.

Так вот в run-time производится загрузка метаданных конфигурации и затем обобщенный алгоритм использует их для парсинга метаданных 1С и создаёт, содержащее метаданные конфигурации (глобальный модуль, диалоговые окна, mxl, ...).

То бишь API умеет в run-time на основании метаданных создавать объекты любой сложности и работать с ними.

Кстати имеются метаданные для файлов Microsoft Office (и они не в ручную были созданы) и API может загружать Excel, ... и сохранять.
Высокоуровневое API для работы с Excel, ... не разрабатывал (не приоритетно).

Удивляют C++-ники.
Лучше всех в форуме умеют «щёки надувать» и вести «умные диалоги».

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 7)
Ответ на: комментарий от annulen

а кто мне потерянные инлайны вернёт и т.п.?

Твои «инлайны» для компилятора давно не более чем пожелания, которые существуют благодаря оставшимся UB, которые отломятся при следующем заворачивании «номального-то кода» в -fpermissive. Манямирок маньяков контроля про «полный контроль» закончился где-то с обретением микрокода и трансляцией CISC в RISC, но они все еще упорото цепляются за иллюзии «чем-то управления», кроме корабля в бутылке.

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

Исключения в c++ — это как вытирать жопу наждачкой

либо не сри в коде, либо потом подорожник приложи :)

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

Частично соглашусь с автором оригинального сообщения, что надо бы хоть вернуть контроль на уровне оптимизаций компилятора. Пример: лично не отказался бы явно задавать no overflow на условие в цикле и при этом использовать unsigned переменную:

for (std::uint32_t i = 0u; [[nooverflow]] i < n; ++i)

Чем помнить тысячу и одну причину почему существует UB в первом месте.

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

Переполнение unsigned это не ub, а вполне законное действие.

Ну и -Wall -Wextra -Werror, а так же ubsan тебе в помощь. Значительную часть проблем они тебе покажут.

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

Переполнение signed это вполне себе UB и сделано для оптимизации. Подобные моменты лучше вынести в явные спецификаторы. Тогда можно будет оптимизацию использовать на любой тип (если компилятор поймет как её оптимизировать). Выше пример написал как это могло бы быть для unsigned типов (можно ещё придумать как это будет выглядеть для итераторов и.т.д.)

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

Я больше про то, что «корифеи плюсов» упорно путают абстрактную машину с реальной и любимые отклонения любимого компилятора от стандарта с «нормальным-то кодом» :)

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

Переполнение signed это вполне себе UB

signed да.

и сделано для оптимизации.

А вот это вряд ли. Сделано это потому что у signed разные варианты дополнения были (как минимум раньше) и что будет при переполнении буквально зависило от реализации. А т.к. это явно ошибка, то объявили ub. И только потом компиляторы начали это оптимизировать, выкидывая проверки и код. Оптимизаторы используют ub, но ub не создавался для оптимизаций. Это свежие веяния, а ub существует уже давно.

Подобные моменты лучше вынести в явные спецификаторы.

#include <cstdint>    
#include <iostream>    
    
    
enum class NOvfInt8: std::int8_t {};    
    
NOvfInt8 operator+(NOvfInt8 lhs, int8_t rhs) {    
    int16_t res = static_cast<int16_t>(lhs) + rhs;    
    if (res > INT8_MAX || res < INT8_MIN) {    
        throw std::exception{};    
    }    
    return NOvfInt8{res};    
}    
    
    
int main() {    
    NOvfInt8 val{0};    
    for (int i = 0; i < 26; ++i) {    
        val = val + 10;    
        std::cout << i << ": " << static_cast<int>(val) << std::endl;    
    }    
}    

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

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

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

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

Спецификатором я уведомляю компилятор, что проверку тут можно выкинуть.

У него и так нет проверок для unsigned. Я не понял, какие именно проверки ты имеешь ввиду. Сравнение с n чтоли?

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

Исключения - это не про обработку ошибок. Название говорит само за себя - ИСКЛЮЧЕНИЕ. Обработка ошибок на их основе - от непонимания инструмента, хотя бы потому, что написания своего кода в духе всяких strong safety guaranty - адский ад. Обработка исключения предполагает радикальные меры - убить/перезапустить/отстегнуть кусок приложухи вместе с данными, которые теперь в хз каком состоянии. Исключения - это такой продвинутый аборт, который не для всей прложухи, а для какой-то его части. Вон растоманы до этого ещё не эволюционировали, вызывают panic если что-то пошло не так, но тут завист от сложности софтины, в простых утилитах это оптимальный вариант.

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

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

Вон растоманы до этого ещё не эволюционировали, ызывают panic если что-то пошло не так

Кстати, а это очень приятно, наверное, когда я заюзал какую-то васянку с условного гитхаба, а оно мне в своих кишках делает аборт, и мой дорогущий станок на АЭС в космосе делают какую-нибудь лютую дичь, убив 100500 человек и ушерб на миллиард денег. Здорово, что они не осилили исключения ))

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

Мои посты в треде в основном о том, что РУЛЯТ АЛГОРИТМЫ, а не стандарты.

когда ты в одно рыло кодишь свои «конфигурации 1С на несколько тысяч строк» - возможно. Когда у тебя проект масштаба онтопикового ядра о паре десятков миллионов тех самых строк и с тысячами разработчиков - ситуация немножко меняется.

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

т.е. добавить «нечто», потом «отрубить все у этого нечто» и шо? зачем все это?!

Затем, зачем и урезать плюсы под ядро. Ты же не хочешь стандартную библиотеку в ядро хочешь тащить?
Или если писать прошивку для контроллера, где памяти хрен да нихрена.
Раст можно урезать по самое ни хочу, отключив не только std, но и так же core. Да он окажется голым, т.е. получим «нулевой рантайм» на который так яростно наяривал небезызвестный Столяров. Но при этом у нас всё так же останется борроучекер и макросы, которые сишечный препроцессор уделывают одной левой.

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

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

Исключения - это не про обработку ошибок.

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

Название говорит само за себя - ИСКЛЮЧЕНИЕ.

Переводчики тоже.

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

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

Жава не интересует, а вот плюсовая либа можно сказать, что не кидает исключения, только если совсем уж капец, скорее что-нибудь сегфолтнится. Мне только одно исключение из правила вспоминается - stoi с братьями, когда не может сконвертить, то бросает исключение. Кривая фигня, не удивлюсь, если станет deprecated.
Резюме - std вполне себе следует данной концепции.

Несогласные быстро раскаются, когда поймут, что вместо данных получают неконсистентное дерьмо, а strong safety guaranty и смежное больно и дорого.

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

В текущем стандарте signed уже является 8 битным с дополнительным кодом, но переполнять его все также нельзя. Я про strict-overflow как в цикле, так и просто в условиях. Хотелось бы вместо указания (или вместе) компилятору флага оптимизации (если выключен) явно указывать компилятору, какой целочисленный тип (signed или unsigned) может быть переполнен. В общем, примерно также, как сделали с restrict. Если сложно, то вот другой пример: нужно, чтобы на каждую переменную (при объявлении) опционально указывался, будет ли к ней применяться правила strict aliasing вместо указания оптимизации в флаге компилятора.

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

Побуду опять адвокатом дъявола и заявлю, что неплохо бы переписать кусок STL, чтобы он возвращал std::optional вместо киданий исключения (привет std::bad_cast, std::bad_weak_ptr, и.т.д.) Их разработчики зачастую забывают обрабатывать, но при этом std::optional не даст никакого over-head’а в 95% случаев.

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

что написания своего кода в духе всяких strong safety guaranty - адский ад

Так-то любая обработка ошибок по-хорошему должна обеспечивать аналог exception safety. Например, если у тебя есть push_back() в вектор, то если что-то пошло не так при добавлении элемента, вектор должен оставаться в прежнем, или хотя бы в адекватном состоянии с сохранением инвариантов.

Тут можно сказать, что обработка кодов возврата/expected вынуждает тебя разносить некоторые операции, типа того, что конструктор никогда не бросает. Но тоже самое можно сделать и с исключениями, если того требует exception safety или чувство прекрасного.

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

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

Ага, только постоянно ходят толки о том, что скорость, zero_cost, и пр. Когда разговор заходит об исключениях. Этот микроскоп используется вместо обработки ошибок.

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

так и просто в условиях

Я вообще не очень понимаю, почему у тебя [[nooverflow]] относится к сравнению и почему ты переполнение ассоциируешь с условиями. По идее оно может относится либо к типу (т.е. к объявлению), либо к операциям над типом (++ и т.п.).

компилятору флага оптимизации (если выключен) явно указывать компилятору, какой целочисленный тип (signed или unsigned) может быть переполнен.

Т.е. ты хочешь, чтобы signed overflow перестал быть ub, а существующие оптимизации компилятора, которые он включает, когда видит, что знаковое будет переполнено включались только для специально помеченных типов?
Какой-то смысл в это есть, но во-первых, тогда уж нужно делать [[overflow]] чтобы по-умолчанию ничего не переполнялось, это всё-таки базовое предположение.
Во-вторых, а какой смысл в переполнении signed. Допустим ты указал, что этот signed может переполнятся, а зачем тебе такое может понадобится? Это ведь в любом случае ошибка.
Ну и для unsigned предположение, что он не может переполняться, наверное, можно было бы включить и отключать его флагом, но лично я не фанат поиска оптимизаций в ub, так что и тут по моему это будет приносить больше вреда или внезапных ошибок, чем пользы.

будет ли к ней применяться правила strict aliasing вместо указания оптимизации в флаге компилятора.

Ну вот указал ты strict для указателя на данные в массиве. Дальше взял на него view (поменял тип, если требуется) и передал массив и view в функцию. Данные пересеклись при strict. Проблема с алиасингом в том, что пересекаются данные или нет становится понятно только при вызове функции.
Какие-то отдельные проблемы алиасинга таким решением, наверное, можно решить, но основная часть останется нетронутой, да ещё и новые добавятся.

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

чтобы он возвращал std::optional вместо киданий исключения (привет std::bad_cast, std::bad_weak_ptr, и.т.д.) Их разработчики зачастую забывают обрабатывать

А optional будут тупо разыменовывать, в точности так же как в расте тупо разыменовывают результат, забивая на обработку ошибок. Разница с растом только в том, что он при разыменовании рухнет, а плюсы таки-бросят исключение (шило на мыло: сразу нельзя было бросить?).

И ещё разница в том, что ловить исключения нужно в гораздо меньшем количестве мест, чем проверять результат. А именно – только в пользовательских точках входа. И забыть сложнее, и кодить не так гиморно. В вебе, например, таковая точка входа – вообще одна. Так что идея с возвратом optional – такое же говно как и раст. (Даже хуже: в случае ошибки раст хотя бы вернёт информацию об ошибке, а не тупо std::nullopt – и догадывайся как хочешь.)

// Я в курсе, что например в scala – Option много где используется. Но там и исключения много где используются. Потому что:

Вернее, так: вы на пару с @kvpfs_2 генерируете какие-то свои фантазии, хотя правило, когда юзать исключения, а когда код возврата/optional/etc., тыщу лет известно и общепринято: если ошибка является частью нормального workflow т.е. бизнес-логики (например, юзер не заполнил обязательное поле) – это код возврата; если это нештатная ситуация (ошибка в программе, или например база отвалилась) – исключение. И продиктовано это правило простым соображением баланса сложности и скорости: исключения медленнее, чем код возврата, но используются сильно реже. В смысле, бросаются в рантайме сильно реже. А в исходном коде количество дурацких проверок в каждой строчке сокращается на порядки.

std::optional не даст никакого over-head’а в 95% случаев.

Да щаз.

static_assert(sizeof(std::optional<int64_t>) == 2 * sizeof(int64_t));

И даже если запихать это в packed-структуру, один сраный булев флаг будет по-прежнему занимать 8 байт (согласно выравниванию хранимого типа).

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

Например, если у тебя есть push_back() в вектор

СТД’ые сущности нет смысла обсуждать, они сделаны с «запасом прочности», ну на всякий случай.

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

Т.е. вместо проверки кодов возврата вы предлагаете делать:

try {
  do_this();
} catch(...) {}
try {
  do_that();
} catch(...) {}
...

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

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

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

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

Есть в Си макрос, который развернёт структуру в ProtocolBuffers? Что-то мне подсказывает, что без генератора не обойтись.

У Раста макросы мощные.

thegoldone
()

Стоило Линусу всего на неделю остаться без электричества из-за метели (╯°□°)╯︵ ┻━┻

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

СТД’ые сущности нет смысла обсуждать, они сделаны с «запасом прочности», ну на всякий случай.

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

Т.е. вместо проверки кодов возврата вы предлагаете делать:

Нет, я предлагаю разносить операции, если это требуется для для обеспечения корректности состояния. С do_this() пример не прокатит, т.к. из него совершенно не очевидно, на кой чёрт там что-то разносить, т.к. неизвестно что он делает.
Классический пример тут это void pop() и T front() вместо T pop(). Не так удобно, но ни при каких обстоятельствах не теряет данные.

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

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

Ну и касательно примера: в самом примере как таковых проблем нет. Если ошибки от do_this() и do_that() должны обрабатываться по-разному, и при этом бросают пересекающиеся исключения, то именно так обработка их ошибок и будет выглядеть.
Правда какое это имеет отношение к сказанному мной не ясно.

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

Какая разница, std или ещё что-то

Потому что стд контейнеры дают сильный_исключительные_гарантии? По причинам озвученным.

Про остальное - вы говорите полнейшую глупость, обеспечить strong safety guaranty в сколько-то сложном случае практически невозможно. Например, имеется массив с объектами, над каждым объектом нужно выполнить действие, по середине прилетает исключение, массив стал невалидным (его модификация неделимая модификация, данные связаны друг с другом). Будете копию массива делать перед операцией? А если в процессе обработки элементов они что-то дергали у других объектов в приложении и там состояние изменилось, как его возвращать? Делать дамп памяти перед каждой функцией?

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

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

Потому что стд контейнеры дают сильный_исключительные_гарантии?

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

вы говорите полнейшую глупость, обеспечить strong safety guaranty в сколько-то сложном случае практически невозможно.

«Сама придумала, сама обиделась.» Он говорил не про strong, а про strong или basic («состояние должно быть прежним или хотя бы корректным»).

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

Он говорил не про strong, а про strong или basic («состояние должно быть прежним или хотя бы корректным»).

Он начал комментировать меня про strong exception safety, а сказано это было как аргумент в пользу неиспользования исключений вместо кодов возвратов. Прилетело исключение - значит вместо данных дерьмо, точка. Если он там что-то свое имел в виду, то ему не стоило меня комментировать.

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

Шутка

Этот пример демонстрирует, что Python умнее C++.
В Python в этом случае значение поместит в тип данных для больших чисел и всё далее будет ok!
А C++ ЗАГНЁТСЯ!

Кстати всё же в API придётся добавить поддержку больших чисел, но пока это не приоритетная задача.

Это всё потому, что C++ не бум бум к использованию метаданных в run-time.
C++ в этом НУБ!

Да только ли в этом?

С++ хорош, если программист понимает его плюсы и минусы и умеет вести разработку надёжной программы.

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

Обработка ошибок на их основе - от непонимания инструмента, хотя бы потому, что написания своего кода в духе всяких strong safety guaranty - адский ад.
обеспечить strong safety guaranty в сколько-то сложном случае практически невозможно.
Не надо путать исключения с кодами возратов.

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

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