All streams
Search
Write a publication
Pull to refresh
21
0
Антон Жилин @Anton3

Бекенд-разработчик

Send message
char = текст ASCII
chat8_t = code unit из UTF-8
int8_t, uint8_t = целые числа
std::byte = неизвестные данные (не текст и не числа)
wchar_t = системный тип символа (привет, ужасы кодировок Windows)
signed char, unsigned char = что угодно в устаревшем коде; стоило бы выпилить
Кажется странным решение, что функция может бросать или только статические исключения, или только динамические. Сравним с Java, где есть checked и unchecked исключения. Обычные динамические исключения хорошо выполняют роль unchecked исключений, когда непонятно, как исправить проблему, но где-то на верхнем уровне имеет смысл всё-таки поймать исключение и обработать. Или сравните с паниками Rust.

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

По-моему, было бы логичнее сделать отдельные варианты throws(E) и throws(E) noexcept. Первый будет пропускать и статические, и динамические исключения. Второй будет пропускать только статические. Причём заворачивать динамическое исключение в std::error стоило бы только явным образом. Не уверен, что это лучшее решение, но что-то мне подсказывает, что для динамических исключений нужна «выделенная полоса».
Речь в существующих Proposal-ах о том, чтобы разделить API аллокаторов на noexcept и не noexcept, а также разделить функции, работающие с аллокаторами, на noexcept и не noexcept. Обрабатывать overcommit в стандарте никто не предлагает. Если вы хотите делать дополнительные проверки, то их надо делать в вашем аллокаторе, плюс использовать новые методы, иначе исключение, выброшенное вашим аллокатором, там же и останется (краш).

Спрашивается, зачем вообще что-то менять, если никому не станет лучше? Дело в том, что как часть плана ухода от динамических исключений, в будущем предлагается сделать максимальную часть стандартной библиотеки noexcept. (Я неточно написал: noexcept предлагается сделать все существующие функции, *которые бросают только из-за памяти*, конечно же.) Чем больше функций noexcept, тем меньше оверхед на поддержку исключений.

P.S. Пишу «уход от динамических исключений», но понятно, что пока это дело необозримого будущего. На вскидку, готово всё будет к C++26, потом ещё будет процесс внедрения новшеств в std, всякие deprecate-obsolete…
Спасибо, поправил. Мне казалось, что уже решили добавить, ан нет — в последнее время про P0323 никаких вестей.
P132 предлагает добавить nothrow версии аллокаторов и nothrow версии std:: функций, использующих аллокаторы. То есть, если всё это когда-нибудь примут, то всё равно нужно будет подсовывать везде свой «кошерный» аллокатор, плюс использовать новые версии методов.
Ответ предназначен NeoCode, промахнулся кнопкой.

Мне нравится, как Intellij Idea подсказывает, на какой строке вызывается корутина в Kotlin:

image

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

Идеальная система исключений — сложно сказать, я не эксперт в этом ;) Хотя в разделе «Когда что использовать» написаны гайдлайны, эквивалентные тем, что сейчас используются в Swift. То есть для преобразования строки в число рекомендуется не пользоваться исключениями, потому что «в строке нет числа» — не ошибка. А вообще, в современных языках программирования наблюдается переход от динамических исключений к статическим. И `throws` в контексте C++ всё же нужен как подсказка программисту.

Что меня расстраивает — в текущем Proposal не предусмотрены cast-ы статических исключений. Закастить можно, но только один раз, к `std::error`, при этом от исключения остаётся один message, остальное теряется. В идеале, конечно, статические исключения должны быть такими же мощными, как динамические, но с бонусом, что можно очень быстро бросить код ошибки.
Вот уменьшение boilerplate для Си как раз не собираются завозить. В комитете сказали, что если в Си когда-нибудь будут исключения, то явные. В статье приведён пример, как это будет выглядеть. Никакого автоматического проброса, явная проверка `result.failed`. А `finally` можно было бы рассматривать для C++, но там преобладает идеология RAII, поэтому этого тоже не будет.

Edit: Наврал я! Предлагается макрос try, предназначенный для проверки failed и проброса исключения.
Прочитал заголовок, обрадовался, перечитал заголовок, посмотрел на дату, взгрустнул. Согласен с подходом Rust, когда указатели, конечно, не deprecated, но почти на все случаи жизни существуют ссылки и другие безопасные аналоги. Проблема недостатка безопасных аналогов как раз находится в процессе решения: string_view, span, observer_ptr.

Да. Насколько я вижу, по сравнению с Java, в предложенном варианте метаклассов есть, как минимум, 2 ограничения:


  1. Метаклассы применимы только для классов. Поля и методы так аннотировать не получится. Результат — появление метаклассов вроде classx, где из-за одной небольшой фичи приходится добавлять метакласс с её поддержкой
  2. Не более 1 метакласса на класс. Чтобы использовать несколько сразу, придётся писать код вида:
    $class MyClassMeta : classx, value {};
    MyClassMeta MyClass { ... };
Swift 4 и последующие версии будут продолжать методично ломать ваш код :)
Под ABI совместимостью имеется в виду, что можно будет линковать фреймворки, написанные на разных версиях Swift, начиная со Swift 4.
То есть не будет такой ситуации, как с Python, когда вы не можете мигрировать на новую версию языка только потому, что все либы заточены под старую. Не компилируется под новой версией Swift? Ну и ладно, укажу в настройках, чтобы только этот модуль компилировался под старой Swift.
Если строить все структуры данных без динамического выделения памяти, то перемещение займет столько же времени, сколько копирование. То есть ситуация тут напоминает std::array: вроде, быстрее работает, но пользоваться неудобно.
А можете описать, чем intrusive_ptr лучше, чем shared_ptr/make_shared?
Как вариант, использовать кастомный аллокатор с std::unique_ptr.
С помощью шаблонных using pool_ptr и make_pool этот вариант тоже можно прихорошить, по удобству будет во многом не хуже shared_ptr.
Когда будете делать замеры производительности, рассмотрите и этот вариант тоже ;)

Переходя в раздел «ненормальное программирование», можно предложить вообще обходиться без указателей. Иерархию наследования преобразовывать в boost::variant. На практике, конечно, я бы не советовал везде пихать такие «извращения».
На вкус и цвет… Перед тем, как отправить, я прочитал это решение. И всё же, в данном конкретном случае предпочитаю написать более короткий «однострочник».
Создание лямбды с последующей передачей в map не является идиоматическим подходом в Ruby. «Решение с lambda» привычнее переписать так, и не только потому, что лямбда может работать медленнее, чем блок:

rates.map{ |r| [r['CharCode'], r['Value'].to_f / r['Nominal'].to_f] }.to_h
Чем вас не устраивает Boost.Serialize? Функционал похож. Можете пояснить, чем ваша реализация лучше?
Насколько я понял, это просто рандомные keywords и операторы Swift, то есть глубинного смысла нет.
Каюсь, перепутал.
Про проблему, можно рассмотреть 2 случая:

  1. Объект почти сразу же присоединяется к родителю. Можно переписать через третий вариант, у наследников QObject обычно последним параметром можно передать родителя.
  2. Объект проделывает долгий путь до прикрепления к родителю. Вначале создаём через make_unique (или через QSharedPointer, как подсказывают), потом отбираем у unique_ptr владение и сразу же прикрепляем к родителю. Этот момент можно вынести в отдельную функцию.

Если я всё правильно понимаю, проблема решается в рамках всё тех же make-функций. Я не думаю, что второй случай очень частый, но опыт работы с Qt у меня тоже небольшой. Но идею в список рассылки попробую закинуть :)
Забыл я про deleteLater, тогда действительно потребуется QSharedPointer, std::unique_ptr уже не спасёт. Тем не менее, можно реализовать функции-обёртки MakeQObject и MakeQChild так, чтобы писать код вроде:

auto obj1 = MakeQObject<MyObject>();

auto obj2 = MakeQChild<MyObject>(parent);

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

auto obj = make<MyObject>(arguments);

Где make — подходящая функция создания умного указателя. Ответ — да, можно, причём такой код будет безопасным и унифицированным.
Такие выделения памяти также отлично сочетаются с рекомендациями Herb Sutter.

Information

Rating
Does not participate
Location
Люберцы, Москва и Московская обл., Россия
Date of birth
Registered
Activity

Specialization

Backend Developer
Senior
C++
Python
Kotlin
Boost
English
Multiple thread