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)
Ответ на: комментарий от yorshka

Если бы плюсы были такими замечательными, вместо веб-дрисни мы бы пользовались нативным софтом на какой-нибудь Qt.

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

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

Ощущение что С++ погибнет под собственной тяжестью.

Ага, уже лет 20 погибает, но становится только краше. Я без вариантов начну любой новый инженерный проект на плюсах 23.

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

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

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

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

Не вижу связи. А еще ты не прав :)

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

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

Про std::simd можешь почитать вот тут и посмотреть лулзовые тесты тут (github.com).

Довольно печально, но не только std::simd, но и качество выбранных авторами статей аргументов.

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

По остальнрй критике кроме нечитаемых сообщений об ошибках - тоже вопрос доведения до ума связки компилятора + стандартной библиотеки, а не какая-то принципиальная проблема. Если будет опция сборки которая скажет что «simd с шаблонным аргументом 512 сгенерирует avx512, с аргументом 256 - на avx, а с 128 на sse», и аналогично сделает разные ширины вызовов на ARM - я всё шаблонизирую этим параметром, и в точке входа добавлю динамическую диспетчеризацию блока SIMD-вычислений. Вполне рабочее, компромиссное решение. Но, внезапно, остальные упомянутые библиотеки там тоже компромиссные.

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

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

остальные упомянутые библиотеки там тоже компромиссные.

И тут стоит подумать, а что вообще надо тащить в стандартную библиотеку? Если мне нужны возможности SIMD библиотеки, так я в конкретном проекте и подумаю, какие компромиссы меня устроят.

Иметь динамический массив, словарь и хештаблицу с компромиссами — мне ок. Не убдет устраивать — легко заменить на что-то другое. SIMD, ИМХО, штука слишком специфичная и, если надо, СРАЗУ НАДО ПОДУМОТБ. Так просто std::simd на highway уже не заменишь.

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

Часть из перечисленного (например, std::vector, throw-спецификатор, std::aligned_storage) всего лишь является подтверждением тезиса про «не ошибается лишь тот, кто ничего не делает».

Так можно вообще про что угодно написать. Это даже близко не оправдание.

А теперь контр-аргумент: на момент добавления этого C++ уже был далеко не первым языком, в котором бы появились эти возможности, и вполне можно было бы изучить опыт других языков. Можно так же было бы сделать экспериментальные библиотеки и тестировать на них, а не пихать сразу в стандарт по самые гланды. Причём к этому подходу в итоге и пришли, да.

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

Goals

Перевести?

compatibility

Перевести - 2?

Это по внешнему интерфейсу (аргументы командной строки) и общей функциональности. Никак не по кодогену. По кодогену шланг НЕ ставит, не ставил и не будет ставить цели быть "максимально совместимым с гцц". Кодоген gcc шланг видел в гробу и белых тапочках.

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

Так можно вообще про что угодно написать.

И нужно.

Это даже близко не оправдание.

Это ваще 100% отмаза на любую ситуацию. Докажи обратное.

А теперь контр-аргумент: на момент добавления этого C++ уже был далеко не первым языком,

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

Можно так же было бы сделать экспериментальные библиотеки

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

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

Это даже близко не оправдание.

А где вы здесь оправдание нашли? Это не оправдание, это характеристика того, что вы сюда притащили как откровение или наброс. Для тех, кто C++ не видел, может и OK, для C++ников слабенько и уныленько.

на момент добавления этого C++ уже был далеко не первым языком, в котором бы появились эти возможности

Ну вот как раз на Java и посмотрели, типа throw хорошая идея.

Причём к этому подходу в итоге и пришли, да.

std::regex, помнится, был слизан с boost::regex. Но что-то результат так себе.

Теперь вот история повторяется с std::hive.

Так что не уверен в том, что комитет учится на своих же ошибках.

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

А теперь контр-аргумент: на момент создания стандарта там работающих компиляторов было полторы штуки

Только я с 1992-го по 1998-й попользовался в той или иной степени: Borland C++, Visual C++, Watcom C++, Zortech C++ (вроде бы его потом Semantic купил), IBM C++ и GNU C++. И это только под x86.

Так что всего компиляторов было под десяток.

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

Только я с 1992-го

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

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

Никак не по кодогену.

Ты на что отвечаешь? А на ответ к чему ставил фейспалм?

Речь шла о поддержке GNU фич в шланге. О внешнем интерфейсе. Об общей функциональности.

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

Ты на что отвечаешь?

:

Мне вот интересно, какой смысл писать не на GNU C/GNU C++?

Потому что есть clang

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

Речь шла о поддержке GNU фич в шланге.

И как поддержка некоторых гну фич в шланге делает бессмысленным написание кода, например, на шланге?

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

Для тех, кто C++ не видел, может и OK, для C++ников слабенько и уныленько.

Для C++-ников любая критика их любимого языка будет слабенькой и уныленькой, они готовы этим обмазываться и дро^Wрадоваться жизни.

Ну вот как раз на Java и посмотрели, типа throw хорошая идея.

У них зрение -10, что ли? Как раз пример Java отлично показал, что checked exceptions – достаточно паршивая идея, по крайней мере в этой реализации.

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

Как раз пример Java отлично показал, что checked exceptions – достаточно паршивая идея, по крайней мере в этой реализации.

Лет через 10 от релиза самой явы.

Это я ещё не говорю о том, что throw в крестах и яве - это два разных throw.

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

Правильно, а первый черновик стандарта был выкачен в 1990-ом.

Это вряд ли. В 1990-ом Страуструп выпустил Annotated Reference Manual, в котором описал тот C++, который хотел бы иметь. А первые реализации того C++ появились года через 2.

Сам ISO-шный комитет образовался только в 1991-ом.

Степанов над STL начал работать, емнип, в 1992-ом и тогда же начались разговоры о том, чтобы наработки Степанова вошли в стандарт. А то и в 1993-ем.

Расхождения в уровне поддержки стандарта были еще в 2000-вых.

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

Для C++-ников любая критика их любимого языка будет слабенькой и уныленькой,

Нет, вы просто плохо стараетесь.

Как раз пример Java отлично показал, что checked exceptions

В 1998-ом это было еще не очевидно. Тем более, что throw в C++ работал ну вот не так, как в Java. Т.е. какие-то уроки типа извлекли, но все равно получилось говно.

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

Это вряд ли. В 1990-ом Страуструп выпустил Annotated Reference Manual,

Как ты умудряешься возражать и соглашаться одновременно? Этот мануал был взят X3J16 как base line.

r--r--r--
()

@unC0Rr

У меня в проекте:

C++23 + fmt + spdlog + [asio] + nlohmann

Что qt умеет лучше и зачем этот кусок ненужности сегодня кроме случаев когда ты учился в заборопокрасочном пту и ничего больше не осилил?

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

Qt это формошлепство. Я видел запартышей, которые тащут это в эмбед, уволил бы, да в том унылом месте заменить было некем.

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

yorshka
() автор топика

ИМХО, что boost, что STL давно переусложнены и лучше их избегать, написав себе в локальном неймспейсе нужные шаблоны.
Плюсы такого подхода:
1. Не будет ломаться ABI. Текущие реализации STL раскрывают многие типы (вроде std::string) по разному в зависимости от версий и опций компиляторов, из-за чего они категорически непригодны для «стандартных» интерфейсов
2. Код не раздует для улучшения поддержки многопоточности и поддержки новых фич в новых версиях стандарта
3. Возможность самому выбрать оптимальную имплементацию, а не предложенную тулчейном (см. случай с std::regex, когда дефолтная реализация говно или std::format, где в дефолтной реализации нечитаемый код и танцпол)
4. Просто более читаемый код и логи ошибок. Что STL, что boost высирают такую нечитаемую лапшу, что новички в ужасе бегут писать на чём-то другом

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

некоторых

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

Мне вот интересно, какой смысл писать не на GNU C/GNU C++?

Потому что есть clang

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

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

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


UPD: Ааааааааааа прости пожалуйста, а что такое писать, например, на шланге?

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

Нет, вы просто плохо стараетесь.

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

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

Я видел запартышей, которые тащут это в эмбед, уволил бы, да в том унылом месте заменить было некем.

А я реализовывал, и:

  • был доволен сам

  • был доволен шеф

  • были довольны клиенты

BruteForce ★★★★
()

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

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

expected

который по стандарту недостаточно строг. Но в общем ты прав, конечно. Авось поправят.

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

nlohmann

JSON это для макак. Я видел запартышей, которые тащут это куда ни попадя, уволил бы, да в том унылом месте заменить было некем.

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

UPD: Ааааааааааа прости пожалуйста, а что такое писать, например, на шланге?

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

#include <stdbool.h>
#include <stdint.h>

uint8_t shuffle(uint8_t x)
{
    typedef bool AsVec __attribute__((ext_vector_type(8)));

    typedef union {
        uint8_t raw;
        AsVec vec;
    } AsEither;

    AsEither e = {.raw = x};
    e.vec = __builtin_shufflevector(e.vec, e.vec, 4, 1, 5, 0, 2, 3, 7, 6);
    return e.raw;
}
shdown ★★
()
Ответ на: комментарий от BruteForce

Ну а есть код, который собирается только GCC:

#include <stdint.h>

typedef uint32_t Quad __attribute__((vector_size(4 * sizeof(uint32_t))));

Quad add_saturate(Quad v, uint32_t s)
{
    for (int i = 0; i < 4; ++i) {
        if (__builtin_add_overflow(v[i], s, &v[i])) {
            v[i] = -1;
        }
    }
    return v;
}

P.S. Кстати хорошо оптимизируется с -O3 -march=native. Хотя казалось бы, майнфак какой-то.

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

Но это какой-то совсем corner case и это легко обходится через union.

Более критично, что шланг не поддерживает _Decimal64, например.

А вот в шланге много прикольных extension’ов, кто-то даже исключительно под шланг пишет.

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

Как ты умудряешься возражать и соглашаться одновременно?

Я просто никогда не слышал, чтобы ARM считался черновиком стандарта.

ЕМНИП, ISO-шный комитет вообще несколько лет никакого текста стандарта не мог родить. И что-то похожее на черновик – это уже вторая половина 1990-х.

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

То, что он плохо старается

Но ведь он плохо старается.

для C++-ников любая критика их любимого языка будет слабенькой и уныленькой

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

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