company_banner

На шаг ближе к С++20. Итоги встречи в Торонто

    Несколько недель назад состоялась встреча международного комитета по стандартизации C++. На ней люди (в основном) не разменивались на мелочи и совершили несколько больших шагов на пути к С++20.

    image

    Главные новости:

    • Расширению Concepts быть в C++20!
    • Ranges, Networking и Coroutines/сопрограммы: выпущены в эксперимент в виде TS.
    • Модули: черновик TS готов.

    Что всё это значит, как это упростит написание кода и что было ещё — читайте под катом.

    Concepts


    Замечательная вещь под названием Concepts внесена в черновик будущего стандарта С++20. Это большая радость для разработчиков обобщенных библиотек, использующих идиому SFINAE.

    Мотивирующий пример для любителей SFINAE
    В вашей библиотеке есть функции `*_fast` и `*_slow`, принимающие на вход два шаблонных параметра `v` и `data`:

    1. `*_fast` — сильно соптимизированы, но требуют, чтобы следующие операции возвращали T& и были валидны:

          v += data;
          v -= data;
          v *= data;
          v /= data;
      
    2. `*_slow` — медленные, но работают со всеми типами данных.

    Задача — написать функции `*_optimal`, которые используют версию `*_fast`, если это возможно:

    #include <iostream>
    
    template <class Container, class Data>
    void compute_vector_fast(Container& v, const Data& data) {
        std::cout << "fast\n";
        // ...
    }
    
    template <class Container, class Data>
    void compute_vector_slow(Container& v, const Data& data) {
        std::cout << "slow\n";
        // ...
    }
    
    template <class Container, class Data>
    void compute_vector_optimal(Container& v, const Data& data) {
        // ??? call `compute_vector_slow(v, data)` or `compute_vector_fast(v, data)` ???
    }
    

    Без концептов эта задача, например, решается через `std::enable_if_t` и множество нечитаемого шаблонного кода.

    С концептами всё намного проще:

    #include <iostream>
    
    template <class T, class Data>
    concept bool VectorOperations = requires(T& v, const Data& data) {
        { v += data } -> T&;
        { v -= data } -> T&;
        { v *= data } -> T&;
        { v /= data } -> T&;
    };
    
    template <class Container, class Data>
        requires VectorOperations<Container, Data>
    void compute_vector_optimal(Container& v, const Data& data) {
        std::cout << "fast\n";
    }
    
    template <class Container, class Data>
    void compute_vector_optimal(Container& v, const Data& data) {
        std::cout << "slow\n";
    }
    


    Концепты позволяют:

    • писать более простой шаблонный код,
    • выдавать более короткие сообщения об ошибках при использовании неверных шаблонных параметров (в теории, пока что это не так!).

    С концептами уже можно поэкспериментировать в GCC, если использовать флаг -fconcepts, например, тут. Вот последний доступный proposal на Concepts.

    Ranges TS


    Ranges увидят свет в виде технической спецификации. Это значит, что поэкспериментировать с ними можно будет еще до C++20.

    С Ranges можно писать `sort(container)` вместо `sort(container.begin(), container.end())`, нужно только заиспользовать нужный namespace.

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

    #include <vector>
    #include <experimantal/ranges/algorithm>
    namespace ranges = std::experimental::ranges;
    
    int main () {
        // Функция get_some_values_and_delimiter() фозвращает вектор,
        // в котором гарантированно есть число 42
        std::vector<int> v2 = get_some_values_and_delimiter();
    
        // Необходимо найти число 42 и отсортировать все элементы, идущие после него:
        auto it = ranges::find(v.begin(), ranges::unreachable{}, 42);
        ranges::sort(++it, v.end());
    }
    

    Нечто подобное Александреску делал для получения супербыстрого поиска.

    Любителям SFINAE и обобщённых библиотек Ranges тоже принесут счастье, так как они определяют огромное количество концептов: Sortable, Movable, Copyable, DefaultConstructible, Same…

    Можно поэкспериментировать, скачав библиотеку отсюда. Вот последний доступный черновик Ranges.

    Networking TS


    Все, что необходимо для работы с сокетами (в том числе для асинхронной работы), будет выпущено в эксперимент еще до C++20. В основе Networking TS лежит доработанный и улучшенный ASIO.

    Вот пара приятных различий:

    • В Networking TS можно передавать move-only callback. В ASIO для этого надо было на свой страх и риск поплясать с бубном макросом BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS. Так что если у вас есть функциональный объект с unique_ptr, то его можно спокойно использовать для callback.
    • Больше constexpr для базовых типов (например, для ip::address).
    • Вменяемые способы передачи аллокаторов: можно в класс-callback добавить allocator_type и метод allocator_type get_allocator(); можно специализировать шаблон associated_allocator и описать, какие методы класса надо дергать вместо get_allocator().

    Можно поэкспериментировать, скачав библиотеку отсюда. Вот последний доступный черновик Networking.

    Coroutines TS


    Сопрограммы — это «возможность сохранить текущий стек, переключиться на другой стек и поработать там, а потом вернуться». В основном они используются для создания генераторов и асинхронной работы.
    Уточнение от @masterspline
    На самом деле, в стандарт вошла версия от MS, которая stackless. Она никакие стеки не переключает. По сути вошедшая в стандарт версия корутин — это функтор (функциональный объект C++, типа лямбды), который создается компилятором из функции, помеченной как «корутина». Свое состояние stackless корутина, как и функтор, держат в членах класса, а для реализации возможности многократного вызова функции-корутины, определен operatop()(), реализованный в виде конечного автомата типа Duff's device в начале которого идет switch() по текущему состоянию конечного автомата.

    Самый смак получается, если смешать Coroutines TS и Networking TS. Тогда вместо асинхронного нечитабельного кода на +100 строк можно получить то же самое, но на 40 строк:

    #include <ctime>
    #include <iostream>
    #include <string>
    #include <experimental/net>
    
    using net = std::experimental::net;
    using net::ip::tcp;
    
    std::string make_daytime_string() {
        using namespace std; // For time_t, time and ctime;
        time_t now = time(0);
        return ctime(&now);
    }
    
    void start_accept(net::io_context& io_service) {
        tcp::acceptor acceptor{io_service, tcp::endpoint(tcp::v4(), 13)};
    
        while (1) {
            tcp::socket socket(acceptor.get_io_service());
            auto error = co_await acceptor.async_accept(socket, net::co_future);
            if (error) break;
    
            std::string message = make_daytime_string();
            auto& [error, bytes] = co_await async_write(
                socket, net::buffer(message), net::co_future
            );
            if (error) break;
        }
    }
    
    int main() {
        net::io_context io_service;
        io_service.post([&io_service](){
            try {
                start_accept(io_service);
            } catch (const std::exception& e) {
                std::cerr << e.what() << std::endl;
            }
        });
    
        io_service.run();
    }
    

    Но вот плохие новости: такую интеграцию Coroutines TS и Networking TS в стандарт еще не привнесли. Пока что придется реализовывать ее самим.

    С сопрограммами уже можно поэкспериментировать в CLANG-6.0, если использовать флаги -stdlib=libc++ -fcoroutines-ts, например, тут. Вот последний доступный черновик Coroutines.

    Модули


    Подготовлен черновик TS. Дело сдвинулось и есть шансы увидеть модули уже в течение года!

    Что такое модули и почему они лучше заголовочных файлов?
    Когда вы собираете проект, каждый файл cpp может компилироваться параллельно (это хорошо, отличная масштабируемость).

    Однако, как правило, вы используете одни и те же заголовочные фалы в каждом файле cpp. За счет того, что компиляция различных файлов cpp никак не связана друг с другом, при каждой компиляции компилятор разбирает одни и те же заголовочные файлы снова и снова. Именно этот разбор и тормозит (заголовочный файл iostream весит более мегабайта, подключите 20 подобных заголовочных файлов — и компилятору придётся просмотреть и разобрать около 30 мегабайт кода при компиляции одного файла cpp).

    И тут на сцену выходят модули! Модуль — это набор файлов, собранных воедино и сохранённых на диск в понятном для компилятора бинарном виде. Таким образом, при подключении модуля компилятор просто считает его с диска в свои внутренние структуры данных (минуя этапы открытия нескольких фалов, парсинга, препроцессинга и некоторых другие вспомогательные этапы).

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

    И наконец, финальная стадия сборки проекта — линковка. В данный момент линковщик может тратить много времени на выкидывание одинаковых блоков скомпилированного кода (вы написали функцию inline/force_inline, 100 раз её использовали, а компилятор решил её не встраивать — линкер выкинет 99 скомпилированных тел вашей функции и оставит одно). С модулями такого происходить не должно, поскольку файл модуля не будет «вкомпиливаться» внутрь собранного файла cpp.

    Модули в черновике не экспортируют макросы, поэтому будет сложновато использовать их для системных файлов с множеством макросов (`<windows.h>`, я на тебя намекаю!) и поддерживать код, использующий модуль и его старый заголовочный файл (если у вас std::string описан в модуле и в заголовочном файле , то при подключении модуля и заголовочного файла будет multiple definitions, поскольку макрос для include guards не экспортируется из модуля). Это как раз такие модули, за которые вы проголосовали в прошлом посте (ваши голоса мы донесли до комитета).

    Вот последний доступный черновик Modules.

    Мелочи, принятые в C++20


    В C++20 можно будет инициализировать bitfields в описании класса:

    struct S {
        unsigned x1:8 = 42;
        unsigned x2:8 { 42 };
    };
    

    Можно будет понимать платформы endianness стандартными методами:

    if constexpr (std::endian::native == std::endian::big) {
        // big endian
    } else if constexpr (std::endian::native == std::endian::little) {
        // little endian
    } else {
        // mixed endian
    }
    

    Можно будет инициализировать поля структур, прям как в чистом C:

    struct foo { int a; int b; int c; };
    foo b{.a = 1, .b = 2};
    

    У лямбд можно будет явно указывать шаблонные параметры:

    auto bar = []<class... Args>(Args&&... args) {
        return foo(std::forward<Args>(args)...);
    };
    

    Заслуги РГ21


    На встречу в Торонто мы ездили с несколькими предложениями:

    • P0652R0 — конкурентные ассоциативные контейнеры. Комитет хорошо встретил предложение, посоветовал провести эксперименты для улучшения ряда мест, посоветовал улучшения в интерфейсе. Начали работу над следующей версией предложения.
    • P0539R1 — integers, размер (количество байт) которых задаётся на этапе компиляции. Возникли споры по поводу интерфейса (указывать шаблонным параметром биты, байты или машинные слова), так что в следующей итерации необходимо будет привести плюсы и минусы различных подходов.
    • P0639R0 — наше предложение направить усилия в сторону разработки `constexpr_allocator` вместо `constexpr_string + constexpr_vector`. Встретили крайне благосклонно, проголосовали за. Следующие наши шаги — прорабатывать тему вместе с Давидом.
    • P0415R0 — constexpr для std::complex. Предложение было одобрено и теперь находится в подгруппе LWG (вместе с предложением на constexpr для стандартных алгоритмов). Должно быть в скором времени смержено в черновик C++20.

      Зачем вообще эти constexpr?
      В комитете С++ активно работают над идеями рефлексии и метаклассов. Обе эти идеи требуют хорошей поддержки constexpr-вычислений от стандартной библиотеки, так что предложения на добавление constexpr — это в основном задел на будущее, чтобы при принятии в стандарт рефлексии можно было использовать стандартные классы и функции.

      Кроме того, ряду библиотек уже нужны constexpr-функции: [1], [2].

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

    • P0457R0 — starts_with и ends_with для строк. Комитет предложил сделать это в виде свободных функций. Один из присутствующих сказал, что у них в компании есть эти методы и их используют чаще, чем остальные алгоритмы вместе взятые. Все с нетерпение ждут новой версии proposal.
    • P0458R0 — функция contains(key) member для классов [unordered_]map/set/multimap/multiset. Комитету идия пришлась по душе, почти отправили в LWG для внедрения в C++20.

    На подходе


    Обсуждали предложение по форматированию текста, и многим понравились предлагаемые возможности (вероятно, потому, что людям нравится Python):

    fmt::format("The answer is {}", 42);

    Обсуждали ring_span, который по функциональности напоминает boost::circular_buffer, но не владеет элементами (является view над контейнером).

    На подходе битовые операции. Когда их примут, правильным ответом на вопрос «Как подсчитать количество выставленых битов в переменной X?» на собеседованиях станет «std::popcount(X)».

    Планы и прочее


    РГ21 планирует в ближайшее время написать предложения на std::stacktrace (в качестве прототипа послужит Boost.Stacktrace), доработать предложение на std::shared_library и на экспорт символов из динамических библиотек.

    Если у вас есть идеи для C++20, если вы нашли проблемы в C++17/14/11 либо просто хотите подстегнуть разработку той или иной фичи C++ — заходите на сайт рабочей группы stdcpp.ru. Добро пожаловать!

    Есть желание помочь с написанием предложений и внести своё имя в историю? Мы подготовили мини-инструкцию по написанию предложений.
    Яндекс 481,82
    Как мы делаем Яндекс
    Поделиться публикацией
    Комментарии 269
    • +4
      На ней люди (в основном)

      То есть там еще и рептилоиды присутствовали?

      • +3

        Очень интересно, буду ждать с++20.


        Только возник вопрос с сопрограммами. Разве не должна функция start_accept иметь такое определение:


        future_t<void> start_accept(net::io_context& io_service);
        • –5
          Очень интересно, буду ждать с++20.

          Простыню текста или компилятор который её реализует? Если второе — то как он будет называться?

        • +2
          Ура, модули!
          • +9
            Ура модули, ура сопрограммы, ура концепты. Если бы ещё они добавили хотя бы статическую рефлексию, вообще бы с ума сошёл от счастья.
          • +1
            Networking TS ужасен, понимаю, для начала и так сойдет, со временем возможно его улучшат

            предлагаю компании яндекс, открыть код MultiFuture/MultiPromise итд из доклада www.youtube.com/watch?v=cEbGlHNcIl4
            и добавить его в стандарт С++20

            Неблокирующий future/promise намного больше интересен чем Networking TS и Coroutines TS
            • 0
              С этим сейчас экспериментирют несколько людей из комитета. Так что обязательно добавят, но не в ближайшее время.
            • 0

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

              • 0
                есть ссылка на гитхаб ?))
                • 0
                  Нет, есть опыт их использования и портирования boost::corutine под UWP. Писать код с их использованием действительно удобно. Но требуется некоторое привыкание, что некоторые вещи можно сделать очень просто и что использование mutex и иных механизмов блокировки — это антипаттерн. Код становится похож на академический ООП с передачей сообщений.
                  • 0
                    Я не понял, вы входили в команду яндекса где их использовали или портировали для себя похожий функционал?

                    Если есть доступ к тем кто отвечает за этот функционал, поспрашивайте насчет открытия исходников на гитхаб.
            • –1
              А сейчас уже можно прочитать/записать файл имея что-то вроде std::wstring или std::filesystem::path? Насколько я знаю, в C++14 так и не было конструктора, скажем, std::ofstream от wstring или wchar*, а это означает что нет нормального кроссплатформенного способа прочитать файл, если в пути есть non-ASCII символы. Пожалуйста, скажите мне что я отстал от жизни и в C++17 или хотя бы C++20 эта проблема решена.
              • +1
                Вообще если стандартная библиотека считает входную строку utf8, то открывать unicode файл можно. Насколько я понимаю проблема с этим главным образом у windows.
                • 0
                  Не очень понятно, что это означает. Если у меня стоит русская локаль, и я хочу прочитать файл с индийскими буквами, это не сработает, так?
                  Насколько мне известно, в Windows, как раз, проблема была более-менее решена, MSVC просто добавлял конструктор ofstream от wstring, а в GCC/Clang его не было. Короче, слава новым стандартам, теперь можно жить.
                  • +2
                    Если у меня стоит русская локаль, и я хочу прочитать файл с индийскими буквами, это не сработает, так?
                    Сработает. Более того, всё сработает даже если у вас русская локаль, а файл с индийскими буквами нужно открыть в программе, написанной 20 лет назад и об UTF-8 ничего не знающей.

                    Насколько мне известно, в Windows, как раз, проблема была более-менее решена, MSVC просто добавлял конструктор ofstream от wstring, а в GCC/Clang его не было.
                    Я бы скорее сказал, что на Windows эта проблема была создана — и теперь успешно разрулилась. В некотором смысла. В MacOS и Linux проблемы никогда и не было, а на Windows расширение всегда было (хоть и небыло стандартом), так что, в общем, неясно — чего мы достигли.
                    • 0
                      Ок, т.е. если бы в Windows не было нестандартного конструктора, то все бы просто пользовались UTF-8, и были счастливы. А поскольку в MSVC есть ofstream(wstring), все пишут программы с его использованием, и ожидают что это будет работать в других системах. Это и есть проблема.

                      А все стандартные библиотеки поддерживают UTF8 в, скажем, ofstream? Т.е. мне достаточно сделать буфер байтов который начинается с EF BB BF и все будет работать и в linux и в MacOS и в Windows?
                      • +4
                        А поскольку в MSVC есть ofstream(wstring), все пишут программы с его использованием, и ожидают что это будет работать в других системах. Это и есть проблема.
                        Именно.

                        А все стандартные библиотеки поддерживают UTF8 в, скажем, ofstream?
                        В корне неверная постановка вопроса. Не «стандартные библиотеки поддерживают UTF8», а «UTF8 поддерживает все стандартные библиотеки» — для того и сделан.

                        Т.е. мне достаточно сделать буфер байтов который начинается с EF BB BF и все будет работать и в linux и в MacOS и в Windows?
                        Нет. EF BB BF — это ещё одна проблема, созданная Windows.

                        Для того, чтобы всё работало в MacOS, Windows, Android, ChromeOS — и вообще на подавляющем большинстве систем не нужно делать ни-че-го. Просто используйте функции, которые использовали в C 70х, а в C++ — с 80х — и всё.

                        А вот если вам нужен ещё и Windows… тогда у вас проблемы…
                        • 0
                          Ok, вроде понятно. Получается что всё-таки до C++20 нет нормального кроссплатформенного способа. Ибо чтобы заставить Windows интерпретировать мою строку как utf8 нужны пляски с бубном, а в linux — не нужны.
                    • +2
                      ofstream на уровне реализации откроет файл через системное API, на Windows это CreateFileA(char*,...)/CreateFileW(wchar_t*), на linux это open() из POSIX. open(char*, ...) на Linux понимает множество unicode через UTF8. То есть когда вы будете использовать на модном C++ конструктор c wstring, он скорее всего внутри себя будет преобразовать wstring->utf8 и вызывать open() с этим параметром(равносильно тому что вы раньше вызывали конструктор со string с данными UTF8). А вот библиотека на Windows скорее всего в конструкторе string использовала CreateFileA(), т.е. использовала системную локаль, а в конструкторе с wstring — CreateFileW(). (disclaimer: это по большей части мои предположения) Небольшой холиварчик про это есть на utf8everywhere.org

                      Резюмируя: да, теперь будет портабельный передачи юникод путя в ofstream, однако на мой взгляд лучше было бы если бы Windows string конструкторе принимала бы UTF8 а не локальную кодировку.
                      • +3
                        На самом деле обе ОС принимают свою локальную кодировку. Просто на линуксе в какой-то момент кто-то сумел продавить utf-8 в качестве универсальной локальной кодировки — а на винде обратная совместимость.
                        • +1
                          Насколько я помню, в Linux вообще нет такого понятия, как кодировка для имени файла. Имя файла — это просто набор байт, и ничего больше.
                          • –2
                            Видимо да.

                            Интересно есть специальный смысл у разделителя, 0x2f "/". Когда он будет в любом байте, т.е. в Linux нельзя будет создать файл ∯ (0x22 0x2f) прочитал это здесь: unix.stackexchange.com/questions/39175/understanding-unix-file-name-encoding. Получается что используя utf8 строку как имя файла/путь можно получить не тот результат что ожидается.
                            • +5
                              Вы как-то странно поняли проблему. Проблема с символом ∯ была бы в кодировках UTF-16 или UTF-32. Но в тех кодировках проблема будет на самом деле почти с любым символом, ведь там много нулевых байт получается, а они в именах файлов тоже запрещены.

                              В UTF-8 же символ ∯ кодируется как 0xe2 0x88 0xaf, и никаких проблем с его использованием в имени файла не возникает.
                              • +1
                                Да, действительно. Получается что в кодировке UTF8 не может быть такого что байт 0x2f будет где-то посредине символа, поскольку в многобайтовом символе все байты имеют всегда старший бит выставленным, тогда как у 0x2f он равен нулю. Довольно удобно получилось.

                                Ну хорошо, но ведь остается проблема что в open() можно отправить строку которая не является валидной UTF8 строкой и в это случае файл будет создан или открыт. Получается что программа которая читает список файлов должна быть готова к тому что имя какого-нибудь из файлов не будет валидной UTF8 строкой. Так?
                                • +2
                                  Получается что программа которая читает список файлов должна быть готова к тому что имя какого-нибудь из файлов не будет валидной UTF8 строкой. Так?
                                  Да. Но совершенно точно так же в Windows программа должна быть готова к тому, что имя файла не будет валидной UTF-16 строкой.

                                  В обоих случаях это — проблемы GUI, ядро такие «мелочи» не интересует…
                              • +2
                                Вы что-то не то вычитали. Как я уже писал: Не «стандартные библиотеки поддерживают UTF8», а «UTF8 поддерживает все стандартные библиотеки»

                                Да, библиотеки для работы с TUI/GUI пришлось переделывать, так как правило «один байт = один символ на экране» перестало исполняться. Однако 99% кода — это не касается. Никакой ASCII vs UNICODE дихотомии, никаких «legacy» и «modern» программ, никаких изменений в ядре — ничего этого не нужно. Даже подстроки в регулярных выражениях можно в UTF-8 искать старыми функциями (если upcase/lowercase конвертация не нужна).

                                Несколько обидно видеть этот костыль в стандарте в 2020м году — примерно как раз когда можно будет уже наконец со спокойной душой заявлять «наше приложение работает на большинстве распространённых платформ… кроме Windows… и не планируем».

                                Вот в 2003м, когда реально было неясно чем попытка Microsoft'а «удавить всех» закончится — это было бы здорово. Но в 2020м?
                                • +1
                                  Вы точно мне ответили? Я писал о том как open() интерпретирует имя файла на Linux (вне стандартов C/C++ и прочего). Насколько я смог понять open() действительно принимает на вход произвольные бинарные данные и различает только два служебный байта: 0x2f и nul. То есть невалидная UTF8 строка тоже может именем файла. Это то что я прочитал после ответа DistortNeo мне.
                                  • +1
                                    Вы правильно прочитали. Проблема в том, что Windows действует примерно так же (тоже только U+002F, но и U+005C, а также, иногда, U+003A), но при этом основная проблема: можно создать и использовать невалидные (с точки зрения Unicode) имена файлов — осталась.

                                    Поскольку UTF-16 не решает ни одной проблемы, а только создаёт новые — использовать его в новых программах глупо, а так как писать новые программы под Windows всё менее нужно — то странно вносить его поддержку в язык в 2020м году.
                                    • 0
                                      Про то что UTF16 не очень удобен я не спорю, но этот подход:

                                      > то странно вносить его поддержку в язык в 2020м году

                                      я считаю странным. Во-первых поддержку utf16 все же включили в C++17 в конструктор ifstream/ofstream. Во-вторых все же подход в рамках идеологии С++ как я ее вижу был бы обеспечить там где возможно близость к платформе, а не игнорировать существующие реалии с высокой колокольни utf8.
                                      • +2
                                        Во-первых поддержку utf16 все же включили в C++17 в конструктор ifstream/ofstream.
                                        И, как мне кажется, это уже было ошибкой.

                                        Во-вторых все же подход в рамках идеологии С++ как я ее вижу был бы обеспечить там где возможно близость к платформе, а не игнорировать существующие реалии с высокой колокольни utf8.
                                        Странно вы её видите. Не напомните, пожалуйста, в какой операционка функции fopen/fclose реализованы на уровне операционной системы? Или там malloc/free/operator new/operator delete?

                                        Извините, но подход C/C++ — это максимальная переносимость, а никак не «максимальная близость к платформе». Вот если бы они научились ifstream/ofstream использовать WTF-8 на Windows — это был бы нормальный C/C++ подход…

                                        • 0
                                          > Извините, но подход C/C++ — это максимальная переносимость

                                          Я бы с этим поспорил, откуда вы это взяли? С++ это один уровень выше поверх ассемблера в системе. Если я пишу под микроконтроллер я не ожидаю переносимость: программа не запустится на другом микроконтроллере, а С++ мне нужен чтобы не думать в ассемблерных инструкциях. Также, если я пишу для Windows мне лучше для путей использовать UTF16, поскольку это без дополнительных преобразований уходит в системные вызовы.

                                          Если нужна максимальная переносимость, то это лучше Java (Write once, run anywhere, хехе) или другой язык где все реализовано через толстые и надежные абстракции.

                                          Вот что как Страуструп определял основные идеи для C++:

                                          • direct mappings of built-in operations and types to hardware to provide efficient memory use and efficient low-level operations, and

                                          • affordable and flexible abstraction mechanisms to provide user-defined types with the same notational support, range of uses, and performance as built-in types.


                                          Разработка переносимого кода в C++ это некоторое подмножество со своими особенностями. Задача разработчиков std:: как раз в том чтобы было больше прикладных задач можно было бы решить в рамках переносимого кода. То что стандартная библиотека позволяет использовать любые пути к файлам — это довольно неплохо на мой взгляд, разработчик при желании может выбрать вариант который обладает наименьшим оверхедом на его платформе, оставаясь в рамках переносимого кода.
                                          • 0
                                            Java (Write once, run anywhere, хехе)
                                            Именно что хе-хе. У меня сложилось впечатление, что написать реально переносимый код на Java не легче, чем на C++. Я не знаю примеров когда, которые легко написать переносимо на Java и трудно на C++.
                                            • 0
                                              Я скорее проилюстрировать что делают когда переносимость ставят во главу угла: создают некоторую виртуальную машину и API который можно реализовать на всех платформах: в жертву идут вещи вроде производительности или доступности на какой-то платформе, на наборе возможностей в API. В Java кроме переносимости были еще различные цели, так что это может быть не совсем чистый пример.
                                              • 0
                                                Я боюсь вы путаете WORA и переносимость.

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

                                                Если же вы хотите вовлечь разработчика в этот процесс, то у вас появляется CHARS в Форте (а вдруг у вас память нибблами адресуется как на HP 48?) и множество «неопределённых поведений», которых программист должен избегать.

                                                Излишне и говорить что первый процесс порождает гораздо менее переносимые программы — если специально о переносимости не заботится, то и в Java её не будет (ваша программа может захотеть иметь два разных файла «Makefile» и «makefile» в одном каталоге и всё — прощай переносимость).
                                            • +2
                                              Я бы с этим поспорил, откуда вы это взяли? С++ это один уровень выше поверх ассемблера в системе.

                                              c++ как язык преследует цель быть тонким слоем высокоуровневых абстракций. Он всегда задумывался быть переносимым и развивается он в направлении переносимого кода (thread/async/filesystem/net/coroutines)
                                              • +2
                                                Я бы с этим поспорил, откуда вы это взяли?
                                                Вам все источники перечислить? Или достаточно Страуструпа?

                                                С++ был изначально создан на основе C потому что C был flexible, efficient, available и portable. И целью — было не потерять эти качества.

                                                И переносимость красной нитью проходит через весь дизайн языка — снизу доверху.

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

                                                Огромное количество UB в C/C++, в частности — появились как раз для того, чтобы иметь возможность писать переносимые программы с минимальными потерями производительности.

                                                Если нужна максимальная переносимость, то это лучше Java (Write once, run anywhere, хехе) или другой язык где все реализовано через толстые и надежные абстракции.
                                                На этом пути максимальной переносимости, увы и ах, не достичь. Ни Java, ни C# не работают на таком количестве платформ как C/C++ — и это не случайность. Лозунг write once, run anywhere — несомнно хорош, но он возлагает задачу обеспечения переносимости на рантайм, а не на программиста. Результат — ни на микроконтроллерах, ни на суперкомпьютерах Java не испольщуется… а C/C++ — вполне.

                                                Также, если я пишу для Windows мне лучше для путей использовать UTF16, поскольку это без дополнительных преобразований уходит в системные вызовы.
                                                Однако это — непереносимо и именно поэтому достаточно грустно видеть эту фичу в C++17. Впрочем это

                                                То что стандартная библиотека позволяет использовать любые пути к файлам — это довольно неплохо на мой взгляд, разработчик при желании может выбрать вариант который обладает наименьшим оверхедом на его платформе, оставаясь в рамках переносимого кода.
                                                Посмотрим. Я пока довольно скептически к этому отношусь: всё это немного напоминает историю с fopen, где стандартное поведение было призвано нейтрализовать различие в разделителях строки (\r\n vs \n), но на практике в 99% случаев используется спецификатор «b», потому что альтернатива — это странные глюки…
                                                • 0
                                                  > Вам все источники перечислить? Или достаточно Страуструпа?

                                                  Теперь у нас Страуструп спорят со Страуструпом. По вашей ссылке я не увидел что С++ ставит переносимость как наивысший приоритет. Когда переносимость делают наивысшим приоритетом в ущебр производительности и доступности, то получится что-то другое. Тогда и получается что-то вроде «UTF8 — самая правильная кодировка, наш язык поддерживает только ее».

                                                  С/С++ появляется в системе как системный язык, на котором пишется ядро/драйверы. Именно по этой причине он наиболее доступный среди других языков на большем числе платформ. Если бы С/С++ не позволял работать очень близко к железу и платформе, никто бы не выбрал его как системный язык и нельзя было бы хвастаться что С++ доступен больше чем Java. Переносимость С++ в реальном мире — это больше похоже на некоторый хак, как писать код так чтобы он работал на требуемых платформах.
                                                  • +1
                                                    вы никогда не слышали как С называют «кроссплатформеным ассемблером»? Или про posix, единственной целью существования которого является предоставление единого API для разных платформ?

                                                    При использовании только стандартного подмножества с++ программа будет работать одинаково на всех платформах (с поправкой на поддерживаемый функционал, типа std::thread на однопоточных МК). И столько проблем со стандартизацией с++ как раз таки от того, что вся переносимость новшеств должна достигаться не в ущерб производительности.

                                                    Вот что действительно является хаком — так это использование сотен разных системных кодировок в win.
                                                    • 0
                                                      В целом то что вы написали — это примерно то же что и я пытаюсь сказать: «что вся переносимость новшеств должна достигаться не в ущерб производительность», т.е. переносимость тут не наивысший приоритет.

                                                      При использовании только стандартного подмножества с++ программа будет работать одинаково на всех платформах

                                                      В реальности так может быть у mainstream платформ, для многих других будут многочисленные уровни совместимости основанные на макросах или билд-скриптах, собственных реализаций, и других методах (вспомните например ./configure и autotools).
                                                      • 0
                                                        В целом то что вы написали — это примерно то же что и я пытаюсь сказать: «что вся переносимость новшеств должна достигаться не в ущерб производительность», т.е. переносимость тут не наивысший приоритет.
                                                        Спорить о том что есть высший приоритет, а что низший можно до бесконечности. Важно, что пока нет быстрого и переносимого решания — фича в C++ не появляется, а переностися на следующий релиз.

                                                        Microsoft со своими co_await/co_yield на это с размаху вьехал — потому его и послали в C++20 (и не факт что там примут — будет зависеть от того, насколько эффективной реализация на разных платформах окажется).

                                                        вспомните например ./configure и autotools
                                                        Вспоминаю. Как страшный сон. Слава богу поддержка «кривых» платформ, не поддерживающих стандарты, сегодня не актуальна (за исключением embedded, но и там потихоньку «дело движется»)
                          • +3
                            Про это было в предыдущей статье (первая новость): habrahabr.ru/company/yandex/blog/323972

                            std::ofstream(L"Теперь можно открывать файлы с юникодными именами.txt") << u8"Ура!";
                          • +8
                            Тут спойлер
                            Антон, я тебя очень ценю и как специалиста по плюсам и как человека, популяризирующего нужную информацию, и как члена комитета, — в общем в твоих постах и выступлениях мне сказать совсем нечего, зато есть чему поучиться, но тут ты не прав (и еще путаешь stackfull корутины со stackless)…

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

                            Это определение stackfull корутины (которые boost::context). В стандарт вошла версия от MS, которая stackless. Она никакие стеки не переключает. По сути вошедшая в стандарт версия корутин — это функтор (функциональный объект C++, типа лямбды), который создается компилятором из функции, помеченной как «корутина». Свое состояние stackless корутина, как и функтор, держат в членах класса, а для реализации возможности многократного вызова функции-корутины, определен operatop()(), реализованный в виде конечного автомата типа Duff's device в начале которого идет switch() по текущему состоянию конечного автомата.
                            IMHO, это заговор
                            Если бы товарищ Нишанов, когда ездил по миру и рассказывал всем про корутины от MS вместо предложения переписать асинхронный сетевой код так, как это делают обычно (с нереальной вложенностью и без возможности обрабатывать ошибки), реализовал это в виде class с operator()() и вспомогательными функциями (как это на самом деле делает компилятор), то все было бы намного понятнее (в том числе и возможности stackless корутин, которые вошли в стандарт).
                            По сути, принятые в стандарт корутины — это синтаксический сахарок, который позволяет компилятору преобразовать функцию в функтор, причем для простой логики эту функцию можно реализовать в виде лямбды, а если у корутины логика сложная, то она не сильно будет отличаться от вручную написанного функтора.

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

                            Во всех примерах корутин приводится именно генератор, причем его проще и понятнее написать в виде лямбды. При этом у меня всегда возникает вопрос: «Зачем тут корутина?». В общем, такие примеры не добавляют понимания, как эти лямбды работают и для чего они нужны. В реальности, IMHO, в 99.9% случаев, когда предлагают использовать корутины, там гораздо уместнее будет именно лямбда.

                            > Тогда вместо асинхронного нечитабельного кода на +100 строк можно получить то же самое, но на 40 строк

                            Самый распространенный пример — асинхронный ввод/вывод. Если его реализовать на корутинах, сразу становится понятно, что кроме stackless корутин, еще требуется некий сервис, делающий ввод/вывод (со stackfull корутинами он не потребовался бы).
                            Я уже говорил, что это заговор
                            Кстати, насколько я понимаю, в винде он также не нужен, там асинхронный ввод/вывод реализован через проактор в отличие от линуксового реактора (причем только для сети). Т.е. для винды stackless корутины от MS довольно полезны, там для их использования для ввода/вывода либо совсем не нужно дополнительного кода, либо он уже написан. В Linux это не так.

                            Чтобы от моего комментария не создалось неправильного впечатления — резюмирую: корутины полезны, но в стандарт приняли stackless корутины и нужно понимать что это такое, как это работает и где полезно (и еще нужно написать много кода, чтобы их использовать, даже в их родной нише — асинхронном вводе/выводе). Сейчас вокруг них много мифов и недопонимания, даже среди членов комитета.
                            • 0
                              По сути корутины, принятые в стандарт — это lambda v2.0 (лямбда + 3 служебных метода + компилятор преобразует тело функции в конечный автомат по методу Даффа, с помощью switch() или как-то еще).
                              Duff's device
                              Кстати, Duff's device переводится «Метод Даффа», а не как это сделано в ВиКи.
                              • 0
                                это lambda v2.0 (лямбда + 3 служебных метода + компилятор преобразует тело функции в конечный автомат

                                А можно это как-то проиллюстрировать, или есть развернутое объяснение?
                                • 0
                                  Я смотрел выступления Нишанова (его абстракцию с негативными накладными расходами, он ее много раз чатал в разных вариантах) и еще можно тут посмотреть (станет понятно, что корутина для генератора — это просто лямбда с состоянием, которую зовут много раз + обертка в виде итератора, чтобы использовать в Range-based for loop, а корутина для asyncIO — это всего лишь интерфейс для большого количества библиотечного кода, который на самом деле и выполняет ввод/вывод в собственных потоках и, скорее всего, там можно было бы обойтись обычными promise/future). В результате от корутин польза скорее в том, что компилятор совсем не линейный код делает похожим на линейный (зато становится сложнее разобраться, что на самом деле происходит).

                                  Понятного целостного объяснения внутреннего устройства я сам до сих пор не видел.
                                  • +3
                                    На мой взгляд причина стандартизации именно stackless, в том что stackful корутины красиво реализуются библиотечно и без поддержки от компилятора. А ручная реализация stackless это некрасивый switch с goto, как его не прячь.
                                    Вполне возможно что поддержку stackful во временем добавят в стандартную библиотеку.

                                    Интересно, можно ли будет stackless корутину сериализовать?
                              • 0
                                Добавил ваши правки в статью. Спасибо!
                              • +3
                                Битовые операции.
                                Кроме перечисленных в табличке rotl, rotr, popcount, countl_zero, countl_one, countr_zero и
                                countr_one, есть еще такая операция как «bit reverse» — разворот бит в слове (то есть первый бит становится последним, второй — предпоследним и т.д.). В x86 ее нет, но в ARM есть операция RBIT.
                                infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489h/Cihjgdid.html
                                Там же есть REV, REV16 и REVSH, обращающие байты в словах (это для перехода между Big/Little endian, кстати не знаю есть ли в стандарте такое… на ум приходит только htonl, htons, ntohl и ntohs, но насколько они стандартны?). Если делать то делайте сразу все.

                                Еще для битовых вращений было бы прикольно задействовать <<< и >>>, но это уже украшательства.
                                • +2
                                  Да, разворот бит полезен для FFT. Еще для всяких Z-order нужно перемежать биты с нескольких чисел, не помешал бы аналог PDEP/PEXT из x86. Но, для начала, лучше бы стандартизовали сдвиги отрицательных целых, хотя бы для intN_t.
                                • 0
                                  >сопрограммы… сохранить текущий стек
                                  А где он будет сохраняться? Если программа записала что-то в регистры процессора и новая сопрограмма туда тоже что-то хочет записать чтобы выполнить вычисление, то как все это будет работать?
                                  • +1
                                    В случае boost::context — регистры процессора сохраняются в, собственно, стеке. Так же как это происходит и при переключении потоков.

                                    В случае сопрограмм через co_await — компилятор знает про co_await и не оставляет ничего в регистрах процессора при переключении.
                                    • 0
                                      Я имею ввиду что никак не могу понять чем переключение контекста отличается от сопрограмм. Переключение контекста получается полностью дамп всех регистров делает, а у сопрограмм затрагиваются только некоторые регистры?
                                      • 0
                                        Ну, boost::context как раз переключение контекста и делает, отличие от потоков — в кооперативной многозадачности, вы явно управляете на какую задачу переключаться.

                                        У co_await есть более сильное ограничение — у таких сопрограмм нет своего стека, свои локальные переменные они хранят в куче.
                                        • 0
                                          На сколько я знаю фишка сопрограмм именно в том, чтобы избежать затратных переключений контекста. Или все же переключение контекста так же происходит и разница лишь в том, что в сопрограммах можно этим управлять?
                                          • +1

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


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

                                  • –3
                                    Чем дальше, тем больше плюсы превращаются в какой-то ад…
                                    Тогда вместо асинхронного нечитабельного кода на +100 строк можно получить то же самое, но на 40 строк

                                    Уверен, что 100 строк C-ного кода будут понятее, чем приведённый пример…
                                    • +7
                                      А чего непонятного, типичная конструкция от MS — async/await. MS проталкивают давненько и достаточно один раз посмотреть, во что это превращается, так сразу становится понятно. На примере C# очень лего понять.
                                      • +2
                                        Человеку, который не знаком с такими конструкциями, очень тяжело по коду понять, что он делает. У меня большой опыт программирования на разных языках, в том числе и на C/C++, но я долго втыкал в код, чтобы понять, что он делает…

                                        Т.е. претензия именно к тому, что язык всё сложнее и сложнее понять без специальной подготовки…
                                        • +3

                                          Оператор co_await в первом приближении можно рассматривать как оператор который "распаковывает" future: future<T> превращается в T.

                                          • 0
                                            Я понял, что делает код, но это потребовало усилий… В этом претензия, язык становится всё менее и менее понятный… Вернее на нём всё проще и проще написать непонятный код, чтение которого будет требовать больших усилий…
                                          • +6
                                            Человеку, который не знаком с такими конструкциями, очень тяжело по коду понять, что он делает. У меня большой опыт программирования на разных языках, в том числе и на C/C++, но я долго втыкал в код, чтобы понять, что он делает…

                                            Простите, но это уже ваша проблема, а не проблема языка. Асинхронное программирование используется уже в большом наборе мейнстримных языков: C#, Python, JavaScript. Теперь и в С++ завезли.


                                            Если вам требуются усилия для его понимания — поздравляю, ваши знания немного устарели. Просто потратьте немного времени на самообучение.

                                        • +4
                                          Так может вы их просто напишете и покажете?
                                          • –1
                                            Зачем? Откройте исходники nginx, там прекрасно всё написано. В том числе и асинхронная обоработка соединений. Код читается на одном дыхании, рекомендую…
                                            • +5
                                              Не у всех хватает дыхания читать простыни из «простого» сишного кода. Ну и речь не о том, а о ваших словах «Уверен, что 100 строк C-ного кода будут понятее, чем приведённый пример». Без реального сравнения непонятно, откуда такая уверенность может появится у кого-то еще.
                                              • –4
                                                Это же моя уверенность, да, основанная на моём опыте… Я своё мнение выссказываю и оно может не совпадать с вашим… И как я написал выше, мне пришлось долго втыкать в год, чтобы понять, что он делает… И это уже не впервый раз, когда я зависаю на современном C++ коде. Т.е. у меня есть опыт, что код C++ нередко трудно читаемый. С другой стороны, чтение кода C не вызывает у меня ни каких проблем, каким бы сложным он не был. На основании этого я и выссказал своё мнение… Это мнение, а не утверждение, что код C++ всегда и для всех сложнее в понимании, чем код C, а значит, не требует доказательств… Как-то так )))
                                                • +8
                                                  я уверен что китайский язык сложный, я несколько раз пытался втыкать и ничего не понимаю, в тоже время русский язык у меня не вызывает никаких проблем, я не говорю что китайский язык не нужен, но это уже не первый раз когда я с ним сталкиваюсь и не могу понять, это чисто мое мнение не требующее доказательств… как то так ))
                                                  • –1
                                                    Некорректное сравнение. Вы приводите аналогию с китайским языком, подразумевая в аналогии, что он новый и сравнивая с русским, который является родным. Это по-первых. Во вторых, вы забыли указать в налогии «для меня китайский язык сложный», а я акцентировал внимание на том, что это моё мнение…

                                                    Я на C/C++ программирую с 1997 года, т.е. уже около 20 лет… И за 25 лет опыта программирования вообще, программировал на десятке-другом разных языков… Так что не «пробовал китайский», я очень неплохо знаю китайский, но некоторые его диалекты вымораживают меня…
                                                    • +5
                                                      Так я тоже по аналогии проакцентировал на своем мнении

                                                      Опыт в данном случае никакой роли не играет, но я бы на вашем месте вычеркнул у себя из списка С++, вы очевидно его вообще не понимаете

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

                                                      К чему тогда ваше личное мнение к тому что вам трудно понимать современный С++?
                                                      Какие пути решения этой ситуации вы предлагаете?
                                                      Предложить комитету упросить язык С++ для того что бы вы начали его понимать?
                                                      Я предлагаю другое решение, вы возьмете книжку по С++ и освоите те моменты которые вам не понятны.
                                                      • –5
                                                        Так я тоже по аналогии проакцентировал на своем мнении

                                                        Не похоже: «я уверен что китайский язык сложный».
                                                        Опыт в данном случае никакой роли не играет, но я бы на вашем месте вычеркнул у себя из списка С++, вы очевидно его вообще не понимаете

                                                        Доказательства? Возможно для вас это так, мне же знание разных языков помогает. Например, когда-то я программировал на прологе, что помогло в понимании эрланга и хаскеля.
                                                        Вы переходите на личности и судите меня не будучи со мной даже знакомы…
                                                        Возможно вы им пользуетесь как С, поэтому логика применения колбеков что С что С++ для вас легче.

                                                        Ну да, в статье идёт речь о будущем стандарте, в текущем описанное пока не поддерживается…
                                                        К чему тогда ваше личное мнение к тому что вам трудно понимать современный С++? Какие пути решения этой ситуации вы предлагаете?

                                                        Вам, любителю аналогий: «Погода хреновая. К чему это ваше личное мнение? Какие пути решения этой ситуации вы предлагаете?»…
                                                        Я предлагаю другое решение, вы возьмете книжку по С++ и освоите те моменты которые вам не понятны.

                                                        Умерь пыл, мальчик…
                                                        • +6
                                                          ваши высказывание в сторону языка С++ совершенно бесполезные, не понимаете — не используйте
                                                          • +1
                                                            Например, когда-то я программировал на прологе, что помогло в понимании эрланга и хаскеля.

                                                            Кстати, к слову о понимании хаскеля. Я тут вчера как-то наткнулся на синглтоны, обсудим, как они сделаны и зачем они нужны? А то вот конкретно это уже немного выходит из зоны моего комфортного понимания.

                                                            • 0
                                                              Я бы с радостью, но хаскелем интересовался лет 5 назад. Мне язык был интересен, но стало туго со временем и я его задвинул. Поэтому тут я вам ни чем помочь не смогу. То же самое с эрлангом, которым я увлёкся где-то в начале 2000-х, и даже что-то серьёзное писал, но сейчас даже синтаксис не вспомню… Пролог был ещё раньше, где-то в 93-94 годах…

                                                              Языки забываешь, но концепции где-то сидят в голове и всплывают, когда видишь что-то подобное… Помниться пролог мне взорвал мозг не меньше ассемблера :)
                                                    • +3
                                                      Какой смысл был в высказывании мнения, которое вы не можете подтвердить?
                                                      • –4
                                                        Точно такой же, как в высказываниях в статье, которые так же не подтверждаются и не доказываются… Это мнение, а не утверждение, которое требует доказательств…
                                                        • +2
                                                          На самом деле в статье дана ссылка на те самые 100 строк, с которыми производится сравнение. Любой может пойти и посмотреть: www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html

                                                          В вашем же случае идет голословное утверждение.
                                                          • –3
                                                            Я согласен, что по ссылке треш. Вы понимаете разницу между мнением и утверждением?

                                                            Вот обработка соедниений в nginx: github.com/nginx/nginx/blob/master/src/core/ngx_connection.c, куча понятного кода…
                                                            • +1
                                                              Вы понимаете разницу между мнением и утверждением?
                                                              Я не понимаю зачем нужно высказывать мнение, если даже автор не может его подтвердить.
                                                              Вот обработка соедниений в nginx:
                                                              Ну а пример из статьи с этой самой красотой как будет выглядеть? И вообще-то такие потроха нужно сравнивать с потрохами Asio, а не с кодом, который Asio использует.
                                                              • –3
                                                                Я не понимаю зачем нужно высказывать мнение, если даже автор не может его подтвердить.

                                                                Давайте аналогию проведу. Я могу выссказать мнение «кофе — обалденный напиток», а вы его не любите и напишите «кофе горький и невкусный». Мы оба выссказали мнение об одном и том же, в обеих случаях это мнение, которое не требует доказательств, это наше личное восприятие… Как можно подтвердить, что один прав, а другой нет? Точно так же и здесь я выссказал своё мнение…
                                                                • +5
                                                                  Это не верная аналогия. Да и вообще, сам факт того, что приходится прибегать к аналогиям уже показателен.

                                                                  Но давайте попробуем на аналогии: в статье говорится, что варить кофе эспрессо быстрее и удобнее, чем варить в турке. И приводятся примеры и того, и другого. А потом приходите вы и говорите: «что-то я не понимаю, как варить кофе эспрессо, по-моему, если заваривать кофе в чайничке, то будет еще проще и быстрее». И когда вас просят продемонстрировать, как вы будете это делать, вы говорите что «это мое мнение, а вообще вон за углом в знаменитой кофейне так варят и нормально получается».
                                                                  • –1
                                                                    Это не верная аналогия. Да и вообще, сам факт того, что приходится прибегать к аналогиям уже показателен.

                                                                    Почему неверная? Зачем вы выссказываете мнение, если не можете его подтвердить?
                                                                    Но давайте попробуем на аналогии: в статье говорится, что варить кофе эспрессо быстрее и удобнее, чем варить в турке. И приводятся примеры и того, и другого. А потом приходите вы и говорите: «что-то я не понимаю, как варить кофе эспрессо, по-моему, если заваривать кофе в чайничке, то будет еще проще и быстрее». И когда вас просят продемонстрировать, как вы будете это делать, вы говорите что «это мое мнение, а вообще вон за углом в знаменитой кофейне так варят и нормально получается».

                                                                    Эспрессо — это сорт кофе, а не способ приготовления… )))

                                                                    Предлагаю заканчивать этот диспут. Я не хочу доказывать, что мнение не требует доказательств, мне это кажется очевидным…
                                                                    • +3
                                                                      Эспрессо — это сорт кофе, а не способ приготовления…
                                                                      А эспрессо-машины придумали для приготовления кофе только этого сорта.
                                                                      Я не хочу доказывать, что мнение не требует доказательств, мне это кажется очевидным…
                                                                      Очевидным является то, что бездоказательное мнение не имеет никакого веса и смысла его высказывать не было.
                                                                      • –2
                                                                        Я привык к ровно противоположному определению: очевидно, это не то, что невозможно доказать, очевидно — это то, что тривиально можно доказать.

                                                                        Действительно, я был неправ…
                                                                        Очевидным является то, что бездоказательное мнение не имеет никакого веса и смысла его высказывать не было.

                                                                        Очевидным? Где доказательства? Без доказательства вы сами себе противоречите…
                                                                        • 0
                                                                          Очевидным? Где доказательства? Без доказательства вы сами себе противоречите…

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

                                                                          • +4
                                                                            Очевидным? Где доказательства? Без доказательства вы сами себе противоречите…
                                                                            Ну если у вас с логикой всё настолько плохо…

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

                                                                            Приведение же ничем не обоснованного мнения не позволяет сделать ни того, ни другого: как-то маркировать «довод» «это ни из каких разумных посылок не следует, но я „попом чую“ — тут что-то не так» невозможно — откуда оппоненту знать, насколько у вас качественная попа? Соответственно конструктивная дискуссия после этого «довода» кончается и начинается бред.
                                                                        • +3
                                                                          Эспрессо — это сорт кофе, а не способ приготовления… )))
                                                                          Ну то есть о кофе у вас примерно столько же знаний, сколько о C++. Хоть бы Википедию открыли, блин: Эспре́ссо (от итал. espresso[1] ) — метод приготовления кофе путём прохождения горячей воды (около 90 °C) под давлением 8-10 бар через фильтр с молотым кофе

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

                                                                          Какой смысл высказывать мнение, которое вы ничем не можете обосновать? Ничего, кроме бесполезной траты времени дискуссия без обоснований, увы, породить не может…
                                                                          • –2
                                                                            Очевидным является то, что бездоказательное мнение не имеет никакого веса и смысла его высказывать не было.

                                                                            Вот вам, любителю википедии: ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5
                                                                            • +3
                                                                              то есть у Вас есть мнение, но нет аргументов? Так и пишите тогда: «вот моё мнение, основанное чисто на эмоциях».
                                                                              • –1
                                                                                то есть у Вас есть мнение, но нет аргументов? Так и пишите тогда: «вот моё мнение, основанное чисто на эмоциях».

                                                                                Т.е. вы всегда, когда не предоставляете аргументы, добавляете «основанное чисто на эмоциях», так? Интересный вы человек ))))
                                                                                • +3
                                                                                  нет, я просто стараюсь таких мнений, которые не являются аргументированными, в неподходящих местах не выражать. Иначе люди будут пытаться аргументированно его оспорить, терять время зря.
                                                                                  • 0
                                                                                    Как вы определяете, что ваших аргументов будет достаточно, для того, чтобы аргументировать мнение, которое вы собираетесь выссказать?

                                                                                    Как вы определяете, что место для выссказывания мнения является подходящим?

                                                                                    Как вы определяете, до выссказывания мнения, что время будет потеряно?

                                                                                    Зачем вы со мной переписываетесь, ведь мы же, объективно, теряем время?

                                                                                    Предлагаю закончить диспут, а то мы тут увязнем до конца дня, а мне ещё надо поработать на C/C++. Мне было приятно с вами пообщаться ;)
                                                                                    • 0
                                                                                      Как вы определяете, что ваших аргументов будет достаточно
                                                                                      Это субъективно. Если мне кажется, что аргументы весомы можно их высказать, но если мне и самому понятно, что они недостаточно убедительны — возможно лучше воздержаться.
                                                                                      • +2
                                                                                        ещё надо поработать на C/C++

                                                                                        Второй раз уже за вашим авторством это С/С++ вижу, а оно мне глаз немного режет. Опыт говорит, что люди, которые так пишут, на самом деле Так вы на С или на С++ работаете?

                                                                                        • +1
                                                                                          Я люблю C и там, где нет требований писать на плюсах, пишу на чистом C, плюс свои проекты на C. Но обычно требуются плюсы, а потому работаю в основном на плюсах.
                                                                                          • 0
                                                                                            На C++ можно по разному писать, как и на любом другом языке.

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

                                                                                            Интересоваться новинками языка и разобраться в них определённо следует, но кидаться их использовать на следующий день после официального выхода весьма опрометчивое ребячество. Имхо.
                                                                                            • +1
                                                                                              Использовать новинки языка на следующий день после даже не официального выхода, а появления реализаций в компиляторах (что часто бывает до релиза стандарта) в рамках экспериментов в собственных хобби-проектах или прототипах вполне себе разумно. Иначе можно всю жизнь просидеть на С с классами ООП и вставками на ассемблере, пусть и став очень умелым в конкретно этом.
                                                                                              • 0
                                                                                                Ну речь вроде бы о продакшне. К тому же вам может по условию требоваться, чтоб результирующий исполняемый код компилировался и работал на довольно широком круге операционных систем не самых последних версий и без возможности наадминистрировать скажем иную версию gcc и тому подобное. Для кого-то приемлимо вычёркивать такие случаи ещё на этапе проектирования, а для кого-то ровно наоборот.
                                                                                                Что касается развиваться и экспериментировать — это можно только поддерживать. Но есть и разная прикладная реальность.
                                                                              • 0
                                                                                Почему неверная? Зачем вы выссказываете мнение, если не можете его подтвердить?
                                                                                Доказывать уместность аналогии должен тот, кто её привёл, а не наоборот. Если это затруднительно — нужно отказаться от аналогии.
                                                                                • 0
                                                                                  Доказывать уместность аналогии должен тот, кто её привёл, а не наоборот. Если это затруднительно — нужно отказаться от аналогии.

                                                                                  Давайте подиспутируем… Вы будете что-то доказывать, а я вам, в качестве обратной связи буду говорить одно слово «Ложь». Вы будете продолжать доказывать или плюнете? Вот и тут на мою аналогию ответили только «Неверная», не написав почему…
                                                                                  • +3
                                                                                    Вы будете что-то доказывать, а я вам, в качестве обратной связи буду говорить одно слово «Ложь»
                                                                                    Если я приведу аргументы, а Вы ответите просто «ложь», то в глазах рационального наблюдателя, моя позиция выиграет в диспуте.
                                                                                    Вот и тут на мою аналогию ответили только «Неверная», не написав почему
                                                                                    Аналогия — это не аргумент. Аналогия может стать аргументом только в том случае, если обе стороны признают аналогию справедливой. Если оппонент не согласен с тем, что аналогия уместна — от аналогии необходимо либо отказаться, либо сперва убедить оппонента в её уместности. Это сложно, так как аналогию вынужден защищать тот, кто её привёл.
                                                                                    • 0
                                                                                      Если я приведу аргументы, а Вы ответите просто «ложь», то в глазах рационального наблюдателя, моя позиция выиграет в диспуте.

                                                                                      Как можно в диспуте «Погода хорошая» и «Погода плохая» выиграть? Можно только сказать, собрав статистику, что такой-то процент считает погоду хорошей, а такой-то плохой, но истины тут быть не может, потому как это мнение, а не факт.
                                                                                      Аналогия — это не аргумент. Аналогия может стать аргументом только в том случае, если обе стороны признают аналогию справедливой. Если оппонент не согласен с тем, что аналогия уместна — от аналогии необходимо либо отказаться, либо сперва убедить оппонента в её уместности. Это сложно, так как аналогию вынужден защищать тот, кто её привёл.

                                                                                      Согласен, аналогия — это попытка донести информацию иносказательно. Если собеседник выражает несогласие одним лишь «несогласен», как можно вести какой-либо диспут? Я вам об этом и написал, если я каждый раз буду говорить «ложь», диспут зайдёт в тупик…
                                                                                      • +3
                                                                                        Как можно в диспуте «Погода хорошая» и «Погода плохая» выиграть?
                                                                                        Вообще можно, если вы на форуме метеорологов. По сути же, если бы Вы написали, что Ваше мнение о корутинах построено чисто на интуиции — его бы проигнорировали. Максимум можно было бы по голосам за и против к этому комментарию судить о том, сколько людей разделяют вашу оценку.
                                                                                        Если собеседник выражает несогласие одним лишь «несогласен», как можно вести какой-либо диспут?
                                                                                        Если несогласие направлено на аналогию, то диспут нужно продолжать отказавшись от аналогии или привести исчерпывающее доказательство её уместности. Это такая особенность аргументов по аналогии.
                                                                                        • 0
                                                                                          Вообще можно, если вы на форуме метеорологов. По сути же, если бы Вы написали, что Ваше мнение о корутинах построено чисто на интуиции — его бы проигнорировали. Максимум можно было бы по голосам за и против к этому комментарию судить о том, сколько людей разделяют вашу оценку.

                                                                                          Идёт дождь. Мне нужен дождь, чтобы земля увлажнилась, чтобы картошка лучше росла, я утверждаю «погода прекрасная». Вы хотели позагорать на солнышке и утверждаете «погода отвратительная». Кто прав? Мнения противоположные на одно и то же.
                                                                                          По сути же, если бы Вы написали, что Ваше мнение о корутинах построено чисто на интуиции — его бы проигнорировали. Максимум можно было бы по голосам за и против к этому комментарию судить о том, сколько людей разделяют вашу оценку.

                                                                                          Моё мнение было о читабельности современного C++ кода. К корутинам вообще отношусь прекрасно, очень интересное решение. И не думаю, что проигнорировали бы, выссказывание было весьма холиварное и молодые любители C++ наверняка его не проигнорировали бы.
                                                                                          • +1
                                                                                            Кто прав?
                                                                                            Я же сразу написал, что это зависит от контекста. Контекст задаёт целевую функцию, — что такое «хорошая» и что такое «плохая». Если контекст — фермерский клуб, разговор на тему хорошей погоды может быть вполне конструктивным.
                                                                        • +4
                                                                          Вот обработка соедниений в nginx: github.com/nginx/nginx/blob/master/src/core/ngx_connection.c, куча понятного кода…

                                                                          У вас куда-то пропала частица "не".


                                                                          В приведенном вами файле:


                                                                          1. куча директив условной компиляции;
                                                                          2. местами используется вложенность управляющих конструкций в 4 и более слоев;
                                                                          3. несколько функций не влезают в экран по высоте.

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

                                                                          • –1
                                                                            1. Да, но как иначе вы определите, можете вы использовать некоторую функцию или нет? Сушествует ли опция сокета в этой версии ядра или нет? В плюсах точно так же придётся использовать директивы.
                                                                            2. Разве в C++ как-то избавились от этого? С++ в чём-то тут отличается от C?
                                                                            3. И? В С++ такого не бывает?

                                                                            Это не проблемы языка, это особенности стиля программирования конкретного человека и C++ от этого тоже не застрахован.

                                                                            Субъективно, не тяжело, а очень просто. Когда я писал свой первый большой проект на C, лет 10 назад, nginx был моим reference manual по сетевому программированию, код Игоря очень легко читается.
                                                                            • +3
                                                                              Да все бывает. Просто конкретно тот код, который вы привели в качестве эталона понятности — нихрена не понятный.
                                                                              • –2
                                                                                Ну, на вкус и цвет… Я же выссказывал своё мнение, что мне понятнее… И верю, что вам код из статьи более понятен, все мы разные…
                                                                                • +1

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


                                                                                  Простыня кода картинкой

                                                                                  • –3
                                                                                    Очевидно тот, который начался выше. Вы же не с конца читаете код, значит знаете, какой это блок…
                                                                                    • +5

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


                                                                                      Более аккуратный код хорошо читается в любом направлении.

                                                                                      • 0
                                                                                        Ну, я не помню, чтобы мне надо было читать код наоборот ))) Но стиль Игоря мне не очень нравится, много пустого места, я люблю более сжатый код… Хотя и бывают функции на сотни строк, типа FSM для парсинга HTTP.
                                                                                        • –2
                                                                                          Каждому своё. Мне по стилю форматирования приведённая простыня кода, наоборот, нравится.

                                                                                          Одно условие — несколько строк, один вызов функции — несколько строк. Логично же, что для улучшения читаемости они должны быть разделены пустыми строками.

                                                                                          Ну и вертикально ориентированный монитор для чтения такого кода будет очень удобен.
                                                                                    • 0
                                                                                      Используйте IDE с подсветкой блоков (indent guides, vertical lines, ...).
                                                                                      • +2

                                                                                        Для этого придется сначала скачать код с гитхаба.


                                                                                        Так-то хорошая IDE имеет бороться с распухшим кодом, с этим не спорю.

                                                                    • +4
                                                                      вы сравниваете код на си, который не развивается, с кодом на с++, который развивается. Ваши знания с++ устаревают, и виноваты в этом вы.
                                                                      Уверен, что 100 строк C-ного кода будут понятее, чем приведённый пример…

                                                                      На си это будет не 100 строк, а за 400. Их и читать будет сложнее, просто в силу объема, и количество ошибок будет квадратнопропорционально выше
                                                                      • –2
                                                                        вы сравниваете код на си, который не развивается, с кодом на с++, который развивается. Ваши знания с++ устаревают, и виноваты в этом вы.

                                                                        Вы оправдываете читабельнность кода C++ его развитием? Развитие, в моём понимании, должно улучшать, а не ухудшать читабельность кода… Может C и так хорош, потому и не надо его куда-либо дальше развивать.

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

                                                                        На си это будет не 100 строк, а за 400. Их и читать будет сложнее, просто в силу объема, и количество ошибок будет квадратнопропорционально выше

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

                                                                        Вот набросал примерно то же самое на C, обработка HTTP-запросов:
                                                                        #include <ev.h>
                                                                        #include "cor_http.h"
                                                                        
                                                                        void
                                                                        cor_http_server_cb(cor_http_request_t *r, void *arg)
                                                                        {
                                                                            cor_http_response_t res;
                                                                            cor_http_response_init(&res, r);
                                                                            cor_http_response_set_code(&res, 200);
                                                                            cor_http_response_set_body(&res, "answer", 6);
                                                                            cor_http_response_send(&res);
                                                                        }
                                                                        
                                                                        int main() {
                                                                            struct ev_loop *loop = EV_DEFAULT;
                                                                            cor_http_t *http = cor_http_new(loop, "127.0.0.1", 8000, NULL, NULL);
                                                                            if (!http) {
                                                                                return 1;
                                                                            }
                                                                            if (cor_http_start(http, cor_http_server_cb, http) != cor_ok) {
                                                                                cor_http_delete(http);
                                                                                return 1;
                                                                            }
                                                                            ev_run(loop, 0);
                                                                            cor_http_delete(http);
                                                                        }
                                                                        

                                                                        Что тут сложного? Где тут 400 строк и «квадратнопропорционально выше», простите, не понял, что вы этим хотели сказать…
                                                                        • +3
                                                                          Вот это уже больше похоже на нормальный код.

                                                                          Но здесь приведен тривиальный алгоритм, веселье начинается когда нужно, к примеру, в процессе обработки http-запроса сделать запрос к СУБД. Или, еще веселее, пачку запросов в цикле (да, я знаю, делать запросы к СУБД в цикле — дурной тон, но иногда надо).
                                                                          • –1
                                                                            Вот тут и начинается искусство, когда надо сложные вещи «скрыть» и предоставить простой инструмент для выполнения задачи… Мне не приходилось из цикла обработки http-запросов обращаться к базе, как правило, работа с базой висит в отдельном потоке и занимается «синхронизацией» данных из демона в базу и обратно. Но, думаю, можно что-то красивое придумать и для вашей задачи. Будет немногим больше кода чем в статье, но не будет сложно для понимания…
                                                                            • +3
                                                                              Вот в том-то и дело, что где-то это искусство, а где-то для этого есть языковая поддержка.
                                                                              • –1
                                                                                Рано или поздно языковой поддержки перестаёт хватать и всё равно приходится творить… И когда вам надо написать быстрое приложение, вы начинаете отказываться от STL, лямбд и другого сахара… C++ скрывает некоторые сложности по сравнению с C, но это не обходится бесплатно…
                                                                                • +7
                                                                                  И когда вам надо написать быстрое приложение, вы начинаете отказываться от STL, лямбд и другого сахара…
                                                                                  Н-да… Поинтересуйтесь что говорят люди, которым приходится писать быстрые приложения на C++.

                                                                                  Ну правда, сколько уже можно эти байки из начала 90-х годов распространять?
                                                                                  • –4
                                                                                    А что там говорят? По большей части банальные вещи, применимые к любому языку программирования…

                                                                                    Про какие вы байки?
                                                                                    • +5

                                                                                      Байки про отказ от STL и лямбд. Там подробно рассказывается как STL и лямбды замечательно работают в задачах HFT.

                                                                                      • –1
                                                                                        Это от контекста зависит и от того, как вы их используете. Очень многие не знают как внутри устроены контейнеры STL, не знаю какие накладные расходы бывают в лямбдах, язык это всё скрывает…
                                                                                        • +3

                                                                                          Язык это не скрывает, язык это пишет в документации.

                                                                                          • –1
                                                                                            Мой опыт чтения чужого C++ кода говорит об обратном… Хотя, и на C это нередкость…
                                                                                          • +2

                                                                                            Самые вкусные места для работы (по части HFT), что я знаю, любят лямбды (они вообще никакого оверхеда сами по себе не дают, о чём вы?!), обмазываются темплейтами и констекспрами для написания эффективных и поддерживаемых парсеров биржевых данных и тыкают палочкой в Rust.

                                                                                        • +5
                                                                                          А что там говорят? По большей части банальные вещи
                                                                                          Т.е. вы не просмотрели слайдов доклада, но говорите про «банальные вещи, применимые к языку программирования»? В том числе и про использование C++ных шаблонов для получения быстрого кода?
                                                                                          Про какие вы байки?
                                                                                          Про то, что необходимо отказываться от STL для получения быстрого кода. Про лямбды — это вообще шедеврально.

                                                                                          Вы, часом, лямбды с std::function не путаете?
                                                                                          • –3
                                                                                            Т.е. вы не просмотрели слайдов доклада, но говорите про «банальные вещи, применимые к языку программирования»? В том числе и про использование C++ных шаблонов для получения быстрого кода?

                                                                                            Вы у меня за спиной стояли и смотрели, что я делал? Зачем вы мне приписывает то, чего не знаете? Я просмотрел слайды. Но я давно программирую на C и увлекаюсь низкоуровневой оптимизацией, в том числе и на уровне ассемблера, потому для меня то, что там написано — это банально, это самое начало…

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

                                                                                            Вы меня верно поняли, я про STL писал, а не про шаблоны…
                                                                                            • +2
                                                                                              Зачем вы мне приписывает то, чего не знаете?
                                                                                              Я не приписываю, я интересуюсь. У меня вопросики стоят в надежде, что вы проясните ситуацию.
                                                                                              Вы меня верно поняли, я про STL писал
                                                                                              STL уже перестал быть Standard Template Library? Как давно?
                                                                                              • 0
                                                                                                Я не приписываю, я интересуюсь. У меня вопросики стоят в надежде, что вы проясните ситуацию.

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

                                                                                                STL — это контейнеры, итераторы, алгоритмы и т.п., реализованные посредством шаблонов. Т.е. я могу использовать шаблоны, но не использовать элементы STL, скажем, std::vector, std::sort, std::map и т.п.
                                                                                              • 0

                                                                                                Обратите внимание: там на одном из слайдов используется класс std::unique_ptr<>. Этот класс, вообще-то, входит в STL.


                                                                                                Значит, даже в HFT от STL не отказываются.