LINUX.ORG.RU

C++ — туда и обратно, или зачем нужен Boost

 , , ,


2

5

Мой предыдущий тред в Development собрал самое большое число ответов аж с сентября, то есть за последние 9 месяцев, и это лишний раз подтверждает упадок этого форума. Полагаю, кто-то должен это изменить, и поэтому мы с тобой, ЛОР, поговорим сегодня про C++.

Начиная с C++26 вместо std::function вводится пачка новых классов: std::copyable_function, std::move_only_function (доступна с C++23) и std::function_ref. Что же не так с оригинальным std::function, ты можешь спросить? А вот что:

#include <functional>
#include <print>

struct call_me {
    int x = 0;
    void operator()() {
        std::print("x was {}\n", x++);
    }
};

int main() {
    const std::function<void()> f = call_me{};
    f();
}

Несмотря на то, что переменная f объявлена константной (люблю оксюмороны!), у неё есть внутреннее состояние и оно меняется при вызовах. Компилятор это без проблем хавает.

Так вот, ковыряясь в том, зачем и кто вообще смог так насрать себе в штаны сам, я наткнулся на статью ребят, которые подводят список подобных косяков комитета C++, когда фичи живут по 10 лет и объявляются устаревшими.

Небольшой список фич, которые были придуманы, оказались не нужны/бесполезны/вредны и выкинуты:

  • Известный vector<bool>, живущий издревле в STL и про который все говорят, что его надо избегать. Частично заменяется std::bitset.
  • std::auto_ptr. Бесполезен, ломает контейнеры, выкинут на помойку в C++17.
  • Указание исключений у функции в формате throw(X, Y). Так же выкинуто в C++17.
  • std::iterator объявили устаревшим в C++17, собираются удалить в C++26.
  • std::aligned_storage и std::aligned_union добавлены в C++11, объявлены устаревшими в C++23, скоро удалят.
  • Ключевое слово register удалено в C++17, хотя всё ещё доступно в Си.
  • std::get_temporary_buffer и std::raw_storage_iterator удалены в C++20.
  • Потрясающее по эпичности фиаско с интерфейсом для сборщиков мусора. std::declare_reachable сотоварищи были добавлены в C++11. Выяснилось, что сборщики мусора для C++ писать либо никто не умеет, либо никто не хочет, поэтому в C++23 это всё удалили и сделали вид, что ничего не было.
  • Абсолютное безумие вокруг концептов, модулей и поддержки сети. Предложения одобряли, вновь отклоняли, переделывали, и по итогу теми же модулями до сих пор никто не пользуется.
  • Сопрограммы (coroutines). В том виде, в котором они есть в C++, это просто ужас. Достаточно того, что корутины требуют выделения памяти из кучи во время работы, а значит вообще не подходят для случаях, когда требуется серьёзная производительность. Например, в любом коде, требующим работы в реальном времени и не позволяющем делать системные вызовы.

Просто лютый трешак, который никто подчищать пока не собирается:

  • std::regex – лютый тормоз, рекомендуется не использовать.
  • Мертворождённый std::simd, добавленный в C++26 и уже с ходу не нужный вообще никому, потому что код с std::simd в два-три раза тормознее чем со сторонними библиотеками, просто голыми интринсиками, и даже медленнее чем просто цикл for.
  • std::async. Дескруктор ждёт завершения асинка и поэтому может залочить весь код тебе. Наконец починили в C++26, но эта штука была сломана 15 лет.
  • Отвратительно спроектированный <iostream>. Его наконец можно выкинуть и использовать std::print, но не все про это знают.
  • Абсолютно тормозные контейнеры map, set, unordered_map. Вместо первого можно использовать flat_map из C++23. Контейнеры в стандартной библиотеке Rust (BTreeMap) и другие реализации B-Tree Map их обгоняют по производительности, но тем не менее в C++ выбирают убогий дефолт.

Решения многих из этих проблем существуют в Boost и сделаны там гораздо лучше. Но в то же время возникает важный вопрос: зачем вообще нужен настолько плохо спроектированный язык, где каждое следующее поколение инженеров, работающих над ним, отменяет решения предыдущих, а код под новые стандарты часто нужно переписывать если не с нуля, то очень близко к тому? Даже процесс разработки Rust с его поехавшими клоунами в юбках на этом фоне выглядит адекватным.

В общем, всё печально, ЛОР. Такие дела.



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

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

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

все теже эти задачи с qt будут лучше и удобнее решаться

Ложь и провокация. Все эти либы вместе весят 1MB и там идиоматический C++. Qt весит пол гига и ничего удобного в нем нет.

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

попробуйте такой же фокус с фанатами Rust, Oberon или, нипривидихоспади, Lisp.

Фанатов Oberon и Lisp приходится по кладбищам искать. А фанатов ярых Rust на этом форуме просто нет, их забанили или они сами ушли. Я тут под местную публику вбрасываю, если что.

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

А посоны не знали и я заменил почти все эксепшоны в проекте на expected o_O

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

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

Основный рынок Qt сегодня – это embedded. Всякие автомобильные экраны (включая спидометр нынче, да), контрольные панеля для автоматики, тысячи применений этому.

У нас там было какое-то управление подъемными кранами. Без UI, без сети, без ничего зачем надо было бы тащить полгиговую либу. Нормальный человек бы на Си это реализовал, но там наняли заедушника, который ничего больше по жизни не осилил и таскает за собой свой самилучши инструмент везде куда возьмут. И солько еще таких по миру.. Кстати, автомобильный эмбед – тот еще пример помойки, доверху набитой анскильными ламерами.

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

При этом остальные потоки просто помещают логируемые данные в concurrent queue, без блокировок.

нормальный логгер

Ага, и получаете либо переполняющуюся очередь и ООМ либо дроп самых важных сообщений с причиной падения программы, потому что запись в лог асинхронная и причины падения не записались

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

некоторых

Ты хочешь

Я толсто намекаю, что гугл допиливал шланг до паритета с конкретными фичами gcc и msvc для решения своих конкретных задач.

, а что такое писать, например, на шланге?

Где ты раньше был с этим вопросом?

«Писать на шланге» == иметь шланг основным компилятором. А это, на минуточку, вся мобильная разработка, которая не джава, и эппл.

r--r--r--
()
Ответ на: комментарий от BruteForce

Тогда я всё ещё прав.

А в чём именно ты прав-то? Ты тут в треде ни одного тезиса не сделал.

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

гугл допиливал шланг до паритета с конкретными фичами gcc и msvc для решения своих конкретных задач

Какое это имеет отношение к моему комментарию о том, что использование гнутых фич не должно мешать писать на шланге, потому что шланг хочет уметь гнутые фичи?

З.Ы. https://godbolt.org/z/xrPx3xq6f

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

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

идиоматический C++

у тебя опечатка в слове «идиотический»

Qt весит пол гига и ничего удобного в нем нет

мне тоже не нравится qt и использовать его в отрыве от гуйни я бы не стал, но интерфейсы и стиль кода там поудобнее будут, чем в перечисленных либах. Да, это весьма современный c++ и он наверно весь такой, но в этом то и проблема. Оно плохо будет работать на старых тулчейнах или если выставить старые стандарты. fmt вообще под c++17 разваливается на части от некоторых случаев с float, попутно роняя компилятор вечной compile-time рекурсией. А главное это очень сложный код ради совершенно пустяковых задач вроде логгера и форматирования текста

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

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

Но ты не делал такого комментария. Ты спрашивал:

А разве не задача шланга быть максимально совместимым с гцц?

Не понял намёков и пошёл уточнять. Разжёвываю намёк - нет у шланга нет цели всей его жизни быть "максимально совместимым с гцц". У него цель быть совместимым с гцц в том, что нужно гуглу, и эта цель шлангом достигнута.

r--r--r--
()
Ответ на: комментарий от BruteForce

я думаю, хорошим примером гнутых фич были бы не специальные аттрибуты и фичи из хидеров (в случае clang c gnu stl оно вообще нерелевантно), а какие-нибудь VLA и nested функции, а там поведение уже сильно отличается

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

С каких пор знак вопроса в конце предложения влечёт за собой вопрос?

Разжёвываю намёк - нет у шланга нет цели всей его жизни быть «максимально совместимым с гцц». У него цель быть совместимым с гцц в том, что нужно гуглу, и эта цель шлангом достигнута.

Хорошо, я же не спорю с этим. Достигнутой цели хватает, что писать на шланге с гнутыми фичами?

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

Достигнутой цели хватает, чтобы компилировать шлангом все андроиды последние лет 15, и хром последние лет 10 - обе цифры условны, и скорее всего реальные сроки больше.

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

вот от fmt у меня реально бомбит, поскольку принцип его работы проще понять по декомпилу скомпилированного, чем по исходнику. Да, со сложностью использования (первый пример) они вроде разобрались и интерфейс у него удобный относительно. С производительностью скомпилированного кода тоже - он слегка обходит printf. Но ради этого всего код был переусложнён настолько, что в нём за день не разобраться нормально и увеличивает время компиляции (а так же либы, его использующие вроде spdlog) в разы, если не десятки раз. Мне средствами c++ удавалось сделать printf, обгоняющий fmt по скорости работы, но к сожалению время компиляции было не меньше - компиляторы просто не расчитаны на compile-time парсинг строковых шаблонов

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

компиляторы просто не расчитаны на compile-time парсинг строковых шаблонов

Это примерно главная трагедия всех крестов. Года где-то с 5-ого примерно понятно, что для наступления рая на земле нужна рефлексия. Как минимум рефлексия времени компиляции.

r--r--r--
()
Ответ на: комментарий от BruteForce
 /usr/libexec/gcc/x86_64-linux-gnu/15/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu - -march=tigerlake -mmmx -mpopcnt -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -mavx -mavx2 -mno-sse4a -mno-fma4 -mno-xop -mfma -mavx512f -mbmi -mbmi2 -maes -mpclmul -mavx512vl -mavx512bw -mavx512dq -mavx512cd -mavx512vbmi -mavx512ifma -mavx512vpopcntdq -mavx512vbmi2 -mgfni -mvpclmulqdq -mavx512vnni -mavx512bitalg -mno-avx512bf16 -mavx512vp2intersect -mno-3dnow -madx -mabm -mno-cldemote -mclflushopt -mclwb -mno-clzero -mcx16 -mno-enqcmd -mf16c -mfsgsbase -mfxsr -mno-hle -msahf -mno-lwp -mlzcnt -mmovbe -mmovdir64b -mmovdiri -mno-mwaitx -mno-pconfig -mpku -mprfchw -mno-ptwrite -mrdpid -mrdrnd -mrdseed -mno-rtm -mno-serialize -mno-sgx -msha -mshstk -mno-tbm -mno-tsxldtrk -mvaes -mno-waitpkg -mno-wbnoinvd -mxsave -mxsavec -mxsaveopt -mxsaves -mno-amx-tile -mno-amx-int8 -mno-amx-bf16 -mno-uintr -mno-hreset -mno-kl -mno-widekl -mno-avxvnni -mno-avx512fp16 -mno-avxifma -mno-avxvnniint8 -mno-avxneconvert -mno-cmpccxadd -mno-amx-fp16 -mno-prefetchi -mno-raoint -mno-amx-complex -mno-avxvnniint16 -mno-sm3 -mno-sha512 -mno-sm4 -mno-apxf -mno-usermsr -mno-avx10.2 -mno-amx-avx512 -mno-amx-tf32 -mno-amx-transpose -mno-amx-fp8 -mno-movrs -mno-amx-movrs --param l1-cache-size=48 --param l1-cache-line-size=64 --param l2-cache-size=8192 -mtune=tigerlake -fasynchronous-unwind-tables -dumpbase -

Да, у шланга гораздо лучше получается. Но я вообще был удивлён, что он одуплил, что здесь происходит и сгенерировал хоть что-то SIMD’овое и branchless. Ну как бы, vector + address of vector element + __builtin_*_overflow + бранч.

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

Но, чёрт побери, что он делает в реализации через (v == 0 && s > 0)???

Э… это совсем не эквивалентно. Оно эквивалентно только если s == 0 || s == 1.

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

Это условие оригинальной задачи.

Если воспринимать число как дополненное нулями до 4-х цифр, то, наверное, да.

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

ну завезли рефлексию, а толку то?
Тут скорее нужен был бы какой-то мета/макро язык, который не ставил бы настолько колом компиляторы. Либо же оптимизировать исполнение compile-time кода компиляторами.
Кстати, появление parameter pack'ов и unfold'а в своё время позводило значительно ускорить обработку многих шаблонных конструкций т.к уменьшилась необходимость в переборе аргументов через рекурсию. Но много где она ещё есть и нередко пытаются даже бинарным поиском это ускорить, создавая ещё менее читаемый код.

mittorn ★★★★★
()
  • Markdown
Пустая строка (два раза Enter) начинает новый абзац. Знак '>' в начале абзаца выделяет абзац курсивом цитирования.
Внимание: прочитайте описание разметки Markdown.
Используйте Ctrl-Enter для размещения комментария