В начале марта в американском городе Кона завершилась встреча международной рабочей группы WG21 по стандартизации C++ в которой участвовали сотрудники Яндекса.
C++17 "приняли"!
Если быть совсем точным, решили, что пора передавать документ-черновик С++17 в вышестоящий орган ISO, который выпустит его в качестве стандарта, либо отправит обратно для исправления форматирования и некоторых других формальностей.

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

Основное время было посвящено полировке черновика C++17, но несколько небольших и интересных нововведений все же успели проскочить в C++17.


20 лет ждали...


std::ofstream(L"Теперь можно открывать файлы с юникодными именами.txt") << u8"Ура!";


std::optional и сравнения


Операторы сравнения для класса std::optional до последнего дня были описаны как:
template <class T>
bool operator < (const optional<T>&, const T&);
// ...

Что вызывало ошибки компиляции в ряде случаев:

optional<const int> x = 42;
int y = 666;
x == y; // не скомпилируется
...

optional<string> s = "Hello";
s == "Hello"; // не скомпилируется


В Коне эта проблема была исправлена, операторы сравнения приобрели следующий вид:
template <class T, class U>
bool operator < (const optional<T>&, const U&);
// ...

Так что теперь все вышеприведённые примеры будут компилироваться, а сравнение 's == «Hello»' будет работать без создания временного объекта строки.

Deduction guides


Было добавлено множество явных deduction guides, так что теперь следующий код будет собираться:

// Ура! Можно не писать шаблонные параметры.
std::tuple      a = {42, "Hello", 3.14};
std::array      b = {1, 2, 3, 4, 5, 6, 7, 8};
std::pair       c = {42, "Hello"};
std::function   d = [](int i) { std::cout << i; };
std::set        e = {1, 2, 3, 4, 5, 6, 7, 8};

// P.S.: В примерах выше знак '=' тоже можно не писать :)


История успеха std::array
В первоначальной бумаге по интеграции explicit deduction guides в стандартную библиотеку не присутствовал класс std::array.

Но так как этот класс любимый у одного из представителей России в WG21 C++, то мы закатали рукава, вооружились последними компиляторами, написали и оттестировали explicit deduction guides для std::array. После чего результат трудов выслали автору предложения, пообщались с ним в кулуарах и… вуаля!


std::byte


Кого-нибудь смущало, что когда нам нужен массив байт для хранения каких-то бинарных данных у мы заводили «массив беззнаковых букв»? C С++17 у нас будет тип данных std::byte и теперь вместо
unsigned char raw_buffer[buffer_size];
можно писать
std::byte raw_buffer[buffer_size];
.

Мелочи, делающие код компактнее и портабельнее


Множество небольших улучшений было внесено повсеместно в стандарт. Так например:
  • std::filesystem::path был подкручен для того, чтобы он мог корректно работать на платформах, отличных от Windows и POSIX (например, на zOS).
  • std::filesystem::directory_entry научился кешировать информацию от ОС и обходиться одним системным вызовом там, где раньше требовалось 2.
  • std::hash для большинства случаев теперь помечен как noexcept, что сделает размер ваших бинарников меньше (при условии, что вы пользуетесь unordered_* контейнерами).
  • Текст описывающий std::atomic_* функции был сильно переработан, теперь код
    long example(atomic<long> * a) { return atomic_fetch_add(a, 42); }
    гарантированно работает на всех имплементациях.
  • Все переменные-теги и шаблонные переменные были помечены как inline, что устраняет проблемы с потенциальным нарушением ODR. Другими словами, объём и производительность вашего код будут менее зависимы от линкера, работа линкера упростится.


Обсуждения и идеи


Как всегда, несколько подгрупп внутри комитета С++ работали одновременно. Некоторые подгруппы успели разобраться с задачами связанными с C++17, и приступили к продумыванию идей для C++20. Ниже расскажу о некоторых самых интересных обсуждениях.

Numbers TS


Если вы занимаетесь точными науками, разрабатываете сверхнадёжные приложения, участвуете в олимпиадах по программированию, ведете финансовые рассчёты или работаете с огромными числами, то у меня есть для вас хорошие новости. Сформировались планы по выпуску Numbers TS — набора различных классов для разнообразнейшей работы с числами. Вот некоторые кандидаты:
  • wide float — числа с плавающей точкой, где количество машинных слов под хранение числа задаётся на этапе компиляции;
  • wide integers (на основе предложения с stdcpp.ru) — целые числа, где количество машинных слов под хранение числа задаётся на этапе компиляции;
  • ubnbounded floats — числа с плавающей точкой, способные хранить число любой размерности и динамически аллоцирующие память по мере необходимости;
  • unbounded integers — целые числа, способные хранить число любой размерности и динамически аллоцирующие память по мере необходимости;
  • rational — дробные числа;
  • safe numbers — обертки над числами, гарантирующие отсутствие UB на этапе компиляции, либо проверяющие переполнения и UB на рантайме;
  • decimal;
  • small float.

Планы амбициозные, ждать придётся достаточно долго.

operator<=>()


Обсудили operator<=>(). Решено продолжать проработку этого оператора, есть все шансы что к C++20 можно будет писать:
struct foo { /* очень много различных полей */ };

auto operator<=>(const foo&, const foo&) = default; // Сгенерирует все компараторы для сравнения foo c foo
auto operator<=>(const foo&, const char*) = default; // Сгенерирует все компараторы для сравнения foo c const char* и все компараторы для сравнения const char* с foo


Остальное


А еще обсуждали модули, корутины/сопрограммы/«Гор-рутины», контракты, constexpr и constexpr контейнеры, constexpr аллокацию «в куче», плагины и динамическую загрузку библиотек, крутые оптимизации для стандартных контейнеров и много другое. Рассказать всё в одном посте не получится, поэтому мы в РГ 21 планируем небольшую встречу, на которой расскажем о будущем С++ и о С++17 поподробнее. Так же на встрече будет выступать Гор Нишанов — автор корутин для WG21 C++.

Итоги и опрос


C++17 на подходе, ура!

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

Внимание! Некоторым подгруппам международного комитета С++ нужно получить информацию о том, что разработчикам интересно и чем разработчики пользуются, чтобы лучше расставить свои приоритеты.
Итак, вот мини опрос:

Проголосовало 379 человек. Воздержалось 273 человека.

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

Поделиться с друзьями
-->

Комментарии (274)


  1. eao197
    21.03.2017 19:02
    +3

    По поводу плагинов в виде .dll/.so: приходилось использовать и очень активно. Вначале использовались свои обертки вокруг «родного» API OS, затем перешли на работу посредством ACE.


    1. OlegZH
      22.03.2017 15:28
      +1

      А можете сообщить подробности? Коротким сравнительным примером простого кода. Чтобы воочию увидеть суть различий и возможные преимущества/недостатки.


      1. eao197
        22.03.2017 15:34

        Подробности забылись где-то в районе 2004-2005 годов, когда мы заменяли свои древние, самописные велосипеды (которые из которых росли еще со времен OS/2) на ACE. Основная причина была в том, что глупо было тянуть собственные разработки и заниматься их багфиксингом и модернизацией, когда все готовое уже было в ACE. Включая и средства для работы с DLL.


        1. OlegZH
          22.03.2017 15:48

          Скажите, пожалуйста, хотя бы, что такое ACE? ;-)


          1. eao197
            22.03.2017 15:52

            Adaptive Communication Environment — очень крутая для своего времени кросс-платформенная библиотека, абстрагирующая C++ разработчика от низкоуровневых деталей конкретных ОС.

            Сейчас выглядит ну очень олдскульно и зачастую может быть заменена Boost-ом или POCO. Тем не менее, если знаний C++ недостаточно для разбирательства с потрохами Boost-а на какой-нибудь богом забытой платформе, то ACE вполне может быть достойным выбором и сегодня. ИМХО. конечно.


  1. FadeToBlack
    21.03.2017 19:07
    +1

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


    1. Satus
      22.03.2017 04:59
      +1

      А что не так с кодом std? Можно пример?


      1. FadeToBlack
        22.03.2017 05:44
        +19

        Он очень красивый (нет)


            explicit vector(size_type _Count)
                : _Mybase()
                {   // construct from _Count * value_type()
                if (_Buy(_Count))
                    {   // nonzero, fill it
                    _Alty _Alval(this->_Getal());
                    _TRY_BEGIN
                    _Uninitialized_default_fill_n(this->_Myfirst, _Count, _Alval);
                    this->_Mylast += _Count;
                    _CATCH_ALL
                    _Tidy();
                    _RERAISE;
                    _CATCH_END
                    }
                }
        


        1. antoshkka
          22.03.2017 11:57
          +4

          Внимание, вопрос: как вы думаете, а почему код написан именно так? Какие на то причины?


          1. myxo
            22.03.2017 14:56
            +10

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


          1. tridemax
            22.03.2017 21:14

            Просветите нас?


            1. antoshkka
              23.03.2017 12:23
              +12

              Ниже практически всё подметили:
              * нижние подчеркивания перед всем что только можно — чтобы защитить себя от пользователей, пишущих макросы в нижнем регистре
              * вместо throw/try/catch — макросы, так как многие пользователи используют стандартную библиотеку с выключенными исключениями
              * большие и длинные тела if — оптимизация под конкретный компилятор (разработчик знает где у него hot path и знает какую ветку компилятор делает hot path). Некоторые стандартные библиотеки имеют в телах goto по той же причине — знают косяки своего компилятора и написали goto чтобы сгенерировался более оптимальный код
              * Множество макросов так же делают библиотеку юзабельной для разных версий стандарта. Так libstdc++ работает на флагах -std=(gnu++98,gnu++03,gnu++11,gnu++14,gnu++1z,c++98,c++03,c++11,c++14,c++1z), без макросов напободие _GLIBCXX_NOEXCEPT просто не обойтись.
              * Есть макросы, которые позволяют работать без RTTI (так любят делать embedded разработчики)
              * Другие странности форматирования (например после открывающей фигурной скобки отступ в -4 пробела) связаны с очень древними кодовыми базами… когда мониторы были узкие и вся С++ строчка иначе на экран не помещалась
              * Куча плясок с бубном вокруг аллокаторов (поэтому много всякого метапрограммирования и специфичные typedef для указателей, вместо T*). Все для того, чтобы пользовательские аллокаторы с using pointer = fancy-pointers работали
              * Куча плясок с бубном вокруг точек кастомизации — поэтому часть методов помечены как ::std::, другие методы вызываются без указания namespace
              * Много плясок с бубном вокруг исключений — практически всё что пользователь передал в качестве шаблонного параметра может кинуть исключение в любой момент. После такого исключения надо оставаться в валидном состоянии (да, даже если функция хеширования кинула исключения — надо подчистить ресурсы и остаться в валидном состоянии).
              * Некоторые имплементации поддерживают дебажные версии стандартной библиотеки, из-за чего макросов становится еще больше, а странность кода возрастает в угоду производительности в дебажном режиме
              *… (я что-то наверняка забыл)


          1. akzhan
            23.03.2017 01:21
            +2

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

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


            1. sborisov
              23.03.2017 10:33
              +1

              Это не макросы (в коде выше)


        1. eao197
          22.03.2017 12:37
          +3

          В середине 90-х слышал байку, что реализацию STL для MS VC++ писал большой любитель Lisp-а и делал он это на каком-то вполне себе читабельном DSL-е. Из которого уже генерировалось вот этот вот все непотребство с нечитабельными именами. Причем нечитабельные имена были выбраны специально. Вроде как даже несколько причин было для этого: начиная от того, что первые реализации STL должны были работать даже на компиляторах без поддержки namespaces, и заканчивая тем, чтобы не возникало конфликтов имен у пользователей, если кто-то отнаследуется от std::vector и захочет добавить парочку своих атрибутов в класс-наследник.

          Понятно, что байка. Но когда заглядываешь в исходники некоторых реализаций STL в нее начинаешь верить :)

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


          1. mezastel
            23.03.2017 01:59

            Вроде как наследоваться некомильфо из-за отсутствия виртуальных деструкторов, не?


            1. eao197
              23.03.2017 08:18

              Все не так просто. В двух словах: такое наследование не будет проблемой, если нет удаления наследника через указатель на базу. Что, вообще-то говоря, нужно бывает далеко не всегда. Плюс, в современном C++ тот же shared_ptr временами может закрывать и эту проблему.


        1. charypopper
          22.03.2017 12:42

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


          1. KvanTTT
            22.03.2017 12:49

            Будем восстанавливать справедливость :)


        1. ZaMaZaN4iK
          22.03.2017 15:13
          +1

          libc++ приятнее


        1. Satus
          22.03.2017 15:21
          +2

          Честно говоря, не вижу ничего криминального. Для стандартной библиотеки вполне допустимо жертвовать читабельностью ради совместимости и производительности.
          Тем более что ничего непонятного в этом коде нет (и в коде ниже тоже). Любой, кто понимает что такое вектор, с лёкостью прочитает этот код.


        1. sborisov
          23.03.2017 10:32
          +1

          Майерс «Эффективное использование STL»
          http://cpp.com.ru/meyers/ch7.html

          В глаза бросается упоминание шаблона std::_Tree. В Стандарте ничего не сказано о шаблоне с именем Tree, но мы помним, что имена, начинающиеся с символа подчеркивания и прописной буквы, зарезервированы для авторов реализаций. Перед нами один из внутренних шаблонов, используемых в реализации некой составляющей STL.

          Оказывается, практически во всех реализациях STL стандартные ассоциативные контейнеры (set, multiset, map и multimap) строятся на основе базовых шаблонов. По аналогии с тем, как при использовании string в диагностике упоминается тип basic_string, при работе со стандартными ассоциативными контейнерами часто выдаются сообщения с упоминанием базовых шаблонов. В данном примере этот шаблон называется _Tree, но в других известных мне реализациях встречались имена tree и _rb_tree, причем в последнем имени отражен факт использования красно-черных (Red-Black) деревьев, самой распространенной разновидности сбалансированных деревьев, встречающейся в реализациях STL.



          1. OlegZH
            24.03.2017 12:28

            Интересно, а если бы пользователь библиотеки (он же программист) мог бы сам выбирать реализацию шаблонов и алгоритмов, то как это всё выглядело бы?


            1. TargetSan
              24.03.2017 13:16

              Глядя на текущий код реализации, вы действительно хотите это знать?


            1. MikailBag
              24.03.2017 19:00

              Наверное в виде шаблонных параметров.
              Но зачем это может понадобиться?


      1. FadeToBlack
        22.03.2017 05:46
        +14

        Он классный (нет)


            iterator _Insert_n(const_iterator _Where,
                size_type _Count, const value_type& _Val)
                {   // insert _Count * _Val at _Where
         #if _ITERATOR_DEBUG_LEVEL == 2
                if (_VICONT(_Where) != this
                    || _VIPTR(_Where) < this->_Myfirst
                    || this->_Mylast < _VIPTR(_Where))
                    _DEBUG_ERROR("vector insert iterator outside range");
         #endif /* _ITERATOR_DEBUG_LEVEL == 2 */
        
                size_type _Off = _VIPTR(_Where) - this->_Myfirst;
                if (_Count == 0)
                    ;
                else if (_Unused_capacity() < _Count)
                    {   // not enough room, reallocate
                    if (max_size() - size() < _Count)
                        _Xlen();    // result too long
        
                    size_type _Capacity = _Grow_to(size() + _Count);
                    pointer _Newvec = this->_Getal().allocate(_Capacity);
                    size_type _Whereoff = _VIPTR(_Where) - this->_Myfirst;
                    int _Ncopied = 0;
        
                    _TRY_BEGIN
                    _Ufill(_Newvec + _Whereoff, _Count,
                        _STD addressof(_Val));  // add new stuff
                    ++_Ncopied;
                    _Umove(this->_Myfirst, _VIPTR(_Where),
                        _Newvec);   // copy prefix
                    ++_Ncopied;
                    _Umove(_VIPTR(_Where), this->_Mylast,
                        _Newvec + (_Whereoff + _Count));    // copy suffix
                    _CATCH_ALL
                    if (1 < _Ncopied)
                        _Destroy(_Newvec, _Newvec + _Whereoff);
                    if (0 < _Ncopied)
                        _Destroy(_Newvec + _Whereoff, _Newvec + _Whereoff + _Count);
                    this->_Getal().deallocate(_Newvec, _Capacity);
                    _RERAISE;
                    _CATCH_END
        
                    _Count += size();
                    if (this->_Myfirst != pointer())
                        {   // destroy and deallocate old array
                        _Destroy(this->_Myfirst, this->_Mylast);
                        this->_Getal().deallocate(this->_Myfirst,
                            this->_Myend - this->_Myfirst);
                        }
        
                    this->_Orphan_all();
                    this->_Myend = _Newvec + _Capacity;
                    this->_Mylast = _Newvec + _Count;
                    this->_Myfirst = _Newvec;
                    }
                else if ((size_type)(this->_Mylast - _VIPTR(_Where))
                    < _Count)
                    {   // new stuff spills off end
                    value_type _Tmp = _Val; // in case _Val is in sequence
        
                    _Umove(_VIPTR(_Where), this->_Mylast,
                        _VIPTR(_Where) + _Count);   // copy suffix
        
                    _TRY_BEGIN
                    _Ufill(this->_Mylast,
                        _Count - (this->_Mylast - _VIPTR(_Where)),
                        _STD addressof(_Tmp));  // insert new stuff off end
                    _CATCH_ALL
                    _Destroy(_VIPTR(_Where) + _Count,
                        this->_Mylast + _Count);
                    _RERAISE;
                    _CATCH_END
        
                    this->_Mylast += _Count;
                    _Orphan_range(_VIPTR(_Where), this->_Mylast);
                    _STD fill(_VIPTR(_Where), this->_Mylast - _Count,
                        _Tmp);  // insert up to old end
                    }
                else
                    {   // new stuff can all be assigned
                    value_type _Tmp = _Val; // in case _Val is in sequence
        
                    pointer _Oldend = this->_Mylast;
                    this->_Mylast = _Umove(_Oldend - _Count, _Oldend,
                        this->_Mylast); // copy suffix
        
                    _Orphan_range(_VIPTR(_Where), this->_Mylast);
                    _Copy_backward(_VIPTR(_Where), _Oldend - _Count,
                        _Oldend);   // copy hole
                    _STD fill(_VIPTR(_Where),
                        _VIPTR(_Where) + _Count, _Tmp); // insert into hole
                    }
                return (begin() + _Off);
                }


        1. Gorthauer87
          22.03.2017 11:34
          +2

          Ну кроме микрософтовского есть еще и другие, например, libc++. Но в целом причина тут в том, что метапрограммирование на шаблонах родилось весьма стихийно, по просту говоря, создавали их для более простых вещей, а уже в процессе поняли, что их можно использовать куда хитрее, а дальше понеслась.
          Хорошая новость в том, что не обязательно в своем коде писать так-же.


        1. OlegZH
          24.03.2017 12:30

          Что будет, если подвергнуть этот код пресловутому рефакторингу?


      1. FadeToBlack
        22.03.2017 05:48
        +5

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


        1. Antervis
          22.03.2017 06:02
          +1

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


          1. FadeToBlack
            22.03.2017 06:07
            +12

            Я считаю, что именно по прихоти безумцев. Человек в своем уме не мог принять такой кодестайл и именование входных параметров и переменных. Читать его не приходится ровно до первого мисюза какой-нибудь обычной функции. Дальше вываливается пару килобайт ошибок в консоль, которые прочитать невозможно из-за дикого именования, потом я иду смотреть код… И мне приходится его читать!


            1. Antervis
              22.03.2017 06:46
              +6

              Дальше вываливается пару килобайт ошибок в консоль

              Во-первых, метод поиска ошибок через чтение кода стандартной библиотеки наименее эффективен независимо от её кода. Ошибка всё-таки у вас, а не там. Во-вторых, пользуйтесь нормальной IDE. В-третьих, грядут концепты, а с ними диагностические сообщения проще. И, последнее, вы приводите код из майкрософтовской реализации и критикуете язык с++ что этот код плохо написан?


              1. FadeToBlack
                22.03.2017 07:34
                +4

                пользуйтесь нормальной IDE

                Какую-такую "нормальную IDE" рекомендует использовать коммитет стандартизации с++? Может они начнут нам рассказывать, какими инструментами нам пользоваться?


              1. FadeToBlack
                22.03.2017 07:38
                +2

                И, последнее, вы приводите код из майкрософтовской реализации и критикуете язык с++ что этот код плохо написан?

                т.е. вот этот код лучше?


                1. Antervis
                  22.03.2017 08:14
                  +1

                  Какую-такую «нормальную IDE» рекомендует использовать коммитет стандартизации с++?

                  При чем тут комитет? Нормальную IDE вам советую я. Причем даже не какую-то определенную
                  т.е. вот этот код лучше?

                  да


                1. 4eyes
                  22.03.2017 16:36
                  +2

                  А ведь libc++, который вам советовали, действительно симпатичнее даже «вот этого» кода.
                  </irony>


            1. encyclopedist
              22.03.2017 16:56
              +3

              Именование переменных такое специально, чтобы их имена не могли пересекаться с вашими. Это даже в стандарте прописано. Сами авторы реализаций постоянно над этим иронизируют, и даже термин придумали — "mandatory uglification". Другой источник "красоты" — это поддержка всевозможных экзотических платформ и доисторических версий, из-за чего количество макросов зашкаливает.


              И да, читать код стандартной библиотеки просто не надо. Достаточно cppreference.com.


              1. 4eyes
                22.03.2017 17:31
                +1

                И настроек компилятора — к слову о _TRY_BEGIN/_CATCH_END


              1. Antervis
                22.03.2017 18:00

                можно легко пережить наличие у std::vector приватного метода с названием _M_default_append. Но вот чего понять не могу: зачем аргументы функций-то с __ начинаются?


                1. encyclopedist
                  22.03.2017 18:04
                  +1

                  Чтобы защититься от вещей вроде #define x.


                  Из неочевидных вещей, от которых стандартной библиотеке приходится защищаться, это например, перегрузка операторов "&" и ","


                1. antoshkka
                  22.03.2017 18:10
                  +2

                  Вы даже не представляете, что порой люди пишут:

                  #define count int // В фирме Одуванчик принято макросы писать с маленькой буквы
                  
                  struct vector {
                      vector(size_t count); // Боль...
                  };
                  


                  1. Antervis
                    23.03.2017 06:30

                    зато у вас самая большая база юнит-тестов.


                1. sborisov
                  23.03.2017 10:35

                  https://habrahabr.ru/company/yandex/blog/323972/#comment_10132820


          1. TargetSan
            22.03.2017 12:16
            +2

            Его не придётся читать как только добавят концепты в основные компиляторы.
            Помню пытался выяснить почему в GCC STL unordered_map не желает принимать incomplete types при декларации. Так и не понял — адская смесь из разных наследующихся друг от друга и от соседского Шарика классов. И без единого комментария — что особо убивает.


            1. xdimka
              22.03.2017 16:06
              +1

              Так это говорит о вашей квалификации, вы не смогли решить задачу, а вместо этого нашли виноватого, библиотеку stl, которую используют миллионы людей


              1. Scf
                22.03.2017 16:26

                Они страдают молча


                1. xdimka
                  22.03.2017 16:42
                  +5

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


                  1. TargetSan
                    22.03.2017 17:10

                    Дайте пожалуйста ссылку на место в документации, где сказано про поддержку incomplete types в различных контейнерах.


                    1. antoshkka
                      22.03.2017 17:25
                      +2

                      В стандарте есть:

                      An incomplete type T may be used when instantiating forward_list if the allocator satisfies the allocator completeness requirements 17.5.3.5.1

                      An incomplete type T may be used when instantiating list if the allocator satisfies the allocator completeness requirements 17.5.3.5.1

                      An incomplete type T may be used when instantiating vector if the allocator satisfies the allocator completeness requirements 17.5.3.5.1


                      Для map и unordered_map гарантий никаких нет. Если хотите добавить — опишите идею на https://stdcpp.ru/proposals


                      1. TargetSan
                        22.03.2017 17:31

                        Спасибо, был не в курсе. К сожалению, честно купленной копии стандарта не имею. А cppreference.com в разделе про unordered_map об этом молчит.


                        1. encyclopedist
                          22.03.2017 17:35
                          +4

                          Вот текущий черновик в удобном для просмотра виде eel.is/c++draft.


                          А вот тут и более старые версии и в виде html, и в pdf.


              1. TargetSan
                22.03.2017 17:07

                Я-то задачу решил — использовав обычный мэп. Я про то, что код нынешних реализаций STL крайне тяжело читать. Что является проблемой, когда надо выяснить подробности такого вот implementation-defined behavior. Которым пестрит половина стандарта.


              1. akzhan
                23.03.2017 01:28

                по факту все-таки иногда приходится смотреть в STL.

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

                unordered_map<const string, string> прекрасно компилируется в GCC 4.9, но падает с ошибкой в Clang 8 (Apple).

                Из-за разной реализации STL.


    1. antoshkka
      22.03.2017 11:40
      +1

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

      А что вы используете в своих проектах вместо стандартной библиотеки?


    1. antoshkka
      22.03.2017 15:41
      +3

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

      А что вы используете вместо стандартной библиотеки (вместо std::vector, std::unordered_map и std::string например)?


      1. FadeToBlack
        22.03.2017 15:42
        -6

        пишу сам


        1. antoshkka
          22.03.2017 15:48
          +5

          А можно посмотреть на ваш string?


          1. FadeToBlack
            22.03.2017 17:09

            У меня для вас плохие новости: вам не понравится. Свой string я писал последний раз в 2006. Те, кто минусует, должны еще раз прочитать фразу "в своих проектах". Это не то же самое, что "везде, где только можно".


          1. FadeToBlack
            22.03.2017 17:14

            вот вам string, вот вам парсер xml, вот вам arraylist. Этому коду 10 лет, так не думайте, что сейчас я пишу так же.


            1. antoshkka
              22.03.2017 17:31
              +2

              В вашей строке ошибка: если вот тут выскочит исключение, то у вас произойдет double free и приложение рухнет.


              1. FadeToBlack
                22.03.2017 17:34
                +2

                если выскочит исключение по выделению памяти, то программа так и так не жилец.


                1. encyclopedist
                  22.03.2017 17:36
                  +1

                  Совсем нет, не надо распространять вредные мифы.


                  https://www.youtube.com/watch?v=QIiFsqsb9HM


                  1. FadeToBlack
                    22.03.2017 17:38

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



                  1. FadeToBlack
                    22.03.2017 17:44

                    Ну и приведите мне приложения, где это РЕАЛЬНО обоснованная трата бюджета разработки? Я делал движок для игрушечек, кого волнует его работоспособность в случае, если не хватило памяти?


                    1. encyclopedist
                      22.03.2017 17:49
                      +3

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


                      • Серверные и любые запросо- или транзакционно-ориентированные приложения. Мы выдадим ошибку в ответ на запрос, вызвавший переполнение памяти, и сервер продолжит работать с остальными запросами.

                      Собственно, там в презентации автор приводит много разных примеров, и положительных и отрицательных.


                      1. soniq
                        26.03.2017 23:10
                        +1

                        Собственно мы же вот прям сейчас можем наблюдать, как эту проблему решили крупнейшие производители софта. Они тупо крашат процесс с документом/вкладкой, надеясь что операционка покрашит один процесс, а остальные это не заденет. И делают вид что так и надо.


                    1. Antervis
                      22.03.2017 18:10

                      Есть много примеров приложений, которые работают на всём доступном объеме оперативы. Например, компиляторы под плисины.


                      1. Scf
                        23.03.2017 08:18

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


                        1. OlegZH
                          30.03.2017 22:04

                          Простите. А Вы не можете мне в двух словах объяснить, что такое «аллокаторы»? Систематическое изучение C++ у меня впереди, и я понимаю, что аллокаторы — это (наверное) какие специальные функции или конструкции, которые выделяют память. Или… это что-то вроде «умных указателей»? (если попал «пальцем в небо», то не отчаивайтесь, а, просто, расскажите своими словами, будет понятнее, потом, читать книжку, а я Вам «спасибо» скажу)))


                          1. Scf
                            30.03.2017 22:47

                            1. STL allocators: https://en.wikipedia.org/wiki/Allocator_(C%2B%2B)
                            2. переопределение operator new/operator delete/operator delete[] с использованием нестандартного менеджера памяти, который работает быстрее за счет увеличения расхода памяти/отказа от многопоточности/использования специфичных для приложения паттернов работы с памятью
                            3. https://ru.wikipedia.org/wiki/Объектный_пул приложение преаллоцирует возможное количество "тяжелых" объектов и пытается работать с тем, что есть.

                            В контексте обсуждения, это, скорее, п.3


            1. encyclopedist
              22.03.2017 18:10

              В вашей строке метод format не реентрабельный (им нельзя пользоваться из разных потоков одновременно).


              1. FadeToBlack
                22.03.2017 18:14

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


            1. Satus
              22.03.2017 18:14
              +1

              А как вы храните в вашем массиве больше int_max элементов, если у вас индексы — знаковые int?


              1. FadeToBlack
                22.03.2017 18:15

                очевидно же, что мне это не требовалось


                1. Satus
                  22.03.2017 18:22
                  +4

                  В этом и отличие кода стандартной библиотеки от обычного.


                  1. FadeToBlack
                    22.03.2017 18:28

                    спасибо, что объяснили


                1. mihaild
                  22.03.2017 18:47
                  +2

                  Очевидно, что ваш код, в отличии от кода стандартной библиотеки, не работает. Понятный неработающий код хуже непонятного работающего.


                  1. FadeToBlack
                    22.03.2017 18:51

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


          1. FadeToBlack
            22.03.2017 17:17

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


            1. Antervis
              22.03.2017 18:50
              +1

              Код stl должен:
              быть const — корректным
              быть exception — корректным
              оптимальным (noexcept, move, минимум аллокаций)
              устойчивым к #define'ам
              удовлетворять требования максимальной алгоритмической сложности для всех методов
              собираться на всех актуальных компиляторах
              собираться при неполной поддержке стандартов
              (при работе с памятью) поддерживать кастомные аллокаторы

              Скольким из этих требований удовлетворяет ваш код?


              1. FadeToBlack
                22.03.2017 18:53
                -2

                Вы разве не умеете читать? Разве я такое утверждал? Разве я говорил, что мой код идеален и его можно использовать везде? Я лишь сказал, что в своих проектах я не использую код, который выглядит ужасно. И который содержит все эти ИЗЛИШКИ, про которые вы только что написали. В чем я не прав? Что вы мне пытаетесь доказать? То, что я и без вас знаю?


                1. OlegZH
                  24.03.2017 12:46
                  +5

                  Скорее всего, подспудно, Вам пытаются донести мысль, что нужно во всём проявлять профессионализм. Если Вы опускаете планку где-то «для себя», то, скорее всего, будете опускать её и «для других». Сие уже настораживает. Как минимум.


              1. OlegZH
                24.03.2017 12:43

                А у меня к Вам немного перпендикулярный вопрос: обязаны ли мы пользоваться шаблонами?

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


                1. Antervis
                  24.03.2017 14:40

                  Но является ли этот подход единственным для реализации стандартной библиотеки?

                  Нет, если тянуть информацию о типах в рантайм или писать на макросах.

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

                  поддержку чего?

                  чтобы семантика выражений всегда гарантировала определённый результат

                  а можно пример, где это не выполняется и где стандарт не помечает поведение как id/ub? Sequence points, емнип, в процессе, можете о них не упоминать

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

                  Модель памяти можно выбирать — используем свои аллокаторы. Какие алгоритмы вы имеете в виду?


                  1. OlegZH
                    24.03.2017 15:05

                    Хорошо. А можно узнать, что такое

                    std::vector
                    — это шаблон или это встроенный тип? Дело в том, что от языка программирования ожидаешь, что в нём самом реализованы основные вычислительные концепции. Кажется, что так должно быть. Или, например, сортировка.Сортировка, как таковая, единственна, но есть множество алгоритмов сортировки. Что с этим делать? В STL мы, просто, вызваем нужный нам алгоритм и всё, так? А если мы хотим иметь пул методов и выбирать по ситуации, какой лучше? По моему, это — увод мною разговора в другую сторону, но я ещё подумаю, что именно меня интересует.

                    P.S. Ещё вспоминаю Borland C++ 5.0, где, вроде бы, были всякие контейнеры, но без шаблонов. Чем так страшно предоставление информации о типах в рантайме? И что будет, если попробовать разобраться в различных способах построения контейнерных типов? Вряд ли такой способ единственен…


                    1. eao197
                      24.03.2017 15:30

                      Вы задаете вопросы, которые отлично разобраны в книге «Дизайн и эволюция языка C++». Пытаться отвечать вам здесь — это как пытаться пересказать изрядную часть этой книги своими словами.


                      1. OlegZH
                        25.03.2017 16:46

                        «Дизайн и эволюция языка C++», говорите? О, это, как раз, то, что мне нужно. Буду читать с карандашом в руках. :-)


                      1. OlegZH
                        25.03.2017 16:47

                        Кстати, а никто не пытался? Это мог быть целый цикл статей на Хабрахабре! Я видел только пару-тройку кратких обзоров.


                    1. Antervis
                      24.03.2017 16:23

                      Хорошо. А можно узнать, что такое
                      std::vector
                      — это шаблон или это встроенный тип?

                      есть простое эмпирическое правило. Видите std:: и не знаете что это — см. документацию.

                      Сортировка, как таковая, единственна, но есть множество алгоритмов сортировки.

                      Вам стандарт дает гарантию, что std::sort выполнится за
                      O(N·log(N)), where N = std::distance(first, last) comparisons.
                      (since C++11)

                      Быстрее, насколько я знаю, не придумали. Если вам нужен какой-то особый алгоритм сортировки, то вам его писать и так и эдак.

                      P.S. Ещё вспоминаю Borland C++ 5.0, где, вроде бы, были всякие контейнеры, но без шаблонов. Чем так страшно предоставление информации о типах в рантайме?

                      производительность ниже в несколько раз


                      1. MikailBag
                        24.03.2017 19:06

                        Вообще говоря, для некоторых частных случаев, быстрее придумали.
                        (Есть алгоритмы сортировки быстрее встроенной в ст. библиотеку).
                        Например, поразрядная сортировка N K-битных чисел работает
                        за O(NK), вместо O(NK log(N)) при использовании std::sort().


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


                        1. Satus
                          24.03.2017 20:15

                          Не существует алгоритмов, основанных на сравнении элементов, которые могут гарантировать меньшее, чем (n*logn) колличество сравнений. Это математически невозможно.

                          Radix sort работает только с данным, которым можно 1 в 1 поставить в соответствие положительное целое число. И в большинстве реальных ситуаций проигрывает quicksort или heapsort как по скорости, как и по памяти.


                          1. MikailBag
                            24.03.2017 20:23

                            Не существует алгоритмов, основанных на сравнении элементов, которые могут гарантировать меньшее, чем (n*logn) колличество сравнений. Это математически невозможно.

                            И как это противоречит моему комментарию?


                            1. Satus
                              24.03.2017 20:27

                              Никак. Я и не говорил, что вы не правы.


                      1. OlegZH
                        25.03.2017 16:58

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


        1. 4eyes
          22.03.2017 16:53

          На эту тему мне очень нравится эпическая драма в двух частях от Dr. Dobbs,
          C++ and The Perils of Double-Checked Locking: Part I
          C++ and The Perils of Double-Checked Locking: Part II
          В которой рассматривается написание потокобезопасеного велосинглтона на С++

          Хотя в С++11 нам упростили жизнь.


  1. Falstaff
    21.03.2017 19:12
    +3

    Кстати, а чем не устроил uint8_t из cstdint? И ещё — понятно, что таких случаев уже не найти, но обычно полагают что байт всё-таки может быть не восьмибитным на некоторых платформах; std::byte будет гарантировать 8, или он тоже будет формально назван платформенно-зависимым?


    1. antoshkka
      21.03.2017 19:16
      +1

      а чем не устроил uint8_t из cstdint

      Тем что это unsigned char и соответственно is_same<uint8_t, unsigned char>::value == true.

      И да, байт может быть не восьмибитным, и такие машины еще есть и работают. В std::byte столько же бит сколько бит в байте на целевой машине.


      1. rafuck
        21.03.2017 19:20

        Но тогда и в unsigned char не 8 бит? В этом случае is_same снова true?


        1. antoshkka
          21.03.2017 19:24
          +2

          is_same сравнивает типы а не их размер.

          std::is_same<int, int>::value                 // true
          std::is_same<int, unsigned int>::value        // false
          std::is_same<int, signed int>::value          // true
          std::is_same<std::byte, char>::value          // false
          std::is_same<std::byte, unsigned char>::value // false
          std::is_same<std::byte, signed char>::value   // false
          

          std::byte — это отдельный не арифметический тип данных.


          1. rafuck
            21.03.2017 19:29

            Я знаю. Хорошо, переформулирую вопрос. На машинах со словом не равным 8 битам (я просто не знаю, простите) uint8_t тоже эквивалентен unsigned char?


            1. antoshkka
              21.03.2017 19:33
              +3

              Зависит от платформы.

              Скорее всего на такой платформе не будет uint8_t, uint16_t, uint32_t, uint64_t. Стандарт С++ говорит что эти алиасы — опциональные.


              1. NelSon29
                22.03.2017 08:58

                В архитектуре NeuroMatrix sizeof(char) == sizeof(short) == sizeof(int). 32-битный байт во всей красе. Таким образом там char и short являются синонимами обычного int.


              1. saluev
                22.03.2017 12:07
                +5

                О, кстати об интах с размером. Можно сделать в будущих стандартах как-нибудь так, чтобы uint_fast8_t вёл себя как int, а не как char, и

                uint_fast8_t num = 17; 
                std::cout << num << std::endl;
                не приводило к консольному апокалипсису?


                1. antoshkka
                  22.03.2017 12:08
                  +2

                  Хороший вопрос. Попробуем решить.


            1. Zuy
              22.03.2017 06:17

              TI TMS320 с размером байта 16 бит, uint8_t в stdint.h отсутствует. Думаю в cstdint его тоже не будет.


              1. rafuck
                22.03.2017 07:40

                Ясно, спасибо.


              1. bearded_guy
                22.03.2017 11:34

                Тоже натыкался на техасовские процы (какой-то из C54xx) и байтовые проблемы: memcpy копирует не по одному байту, а по два, и соответственно размер в нее надо передавать sizeof(var)/2.


                1. encyclopedist
                  22.03.2017 17:01

                  Странно, потому что sizeof обязан выдавать размер в char, то есть в данном случае в 16-битных словах, а не в байтах. На TMS320C40 например, все типы 32-разрядные, sizeof(char) == 1 но CHAR_BITS == 32


                  1. bearded_guy
                    22.03.2017 19:53

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


            1. eiennohito
              22.03.2017 13:41

              Есть такая штука, что например uint8_t* нельзя алиасить к другим указателям.

              https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66110


          1. nckma
            22.03.2017 10:54

            Тогда объясните в каких именно случаях предполагается использовать std::byte, а в каких unsigned char.


            1. Satus
              22.03.2017 15:26

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


        1. kostus1974
          22.03.2017 12:12

          сначала unsigned char не 8 бит. в C byte определяется как unsigned char. так что правильней всегда думать, что байт — это unsigned char, а не пакет из 8-ми бит. на целевой платформе это может быть и 16 бит, и 11 и неизвестно ещё сколько. конкретные биты, их номера, упоминаются уже в ветвях #ifdef… #else… #endif, при реализации работы с битами для конкретных платформ.


      1. eiennohito
        22.03.2017 11:33

        А std::byte* можно будет алиасить с другими типами указателей?


        1. antoshkka
          22.03.2017 11:35

          Да. Для std::byte* те же правила по алиасингу, что и для unsigned char.


  1. rafuck
    21.03.2017 19:17

    При инициализации std::function знак «равно» тоже можно не писать?


    1. antoshkka
      21.03.2017 19:20

      Да, но придется написать скобки

      std::function   d{ [](int i) { std::cout << i; } };
      // или
      std::function   d( [](int i) { std::cout << i; } );
      


      1. rafuck
        21.03.2017 19:20

        Ну, я это и имел в виду ,)


      1. TargetSan
        22.03.2017 12:20

        А эта красота работает только для нескольких стандартных классов? Или пользовательские тоже смогут?


        1. antoshkka
          22.03.2017 12:24

          Работает и для пользовательских. При том из коробки, если шаблонные параметры класса участвуют в конструкторе. Иначе придётся писать explicit deduction guide.


  1. develop7
    21.03.2017 19:37

    Миленько, да. А что выбросили?


    1. antoshkka
      21.03.2017 19:40
      +4

      Весь заголовочный файл <codecvt> помечен как устаревший. В нём находилась вот это:

      namespace std {
        enum codecvt_mode {
          consume_header = 4,
          generate_header = 2,
          little_endian = 1
        };
      
        template<class Elem, unsigned long Maxcode = 0x10ffff,
          codecvt_mode Mode = (codecvt_mode)0>
        class codecvt_utf8
          : public codecvt<Elem, char, mbstate_t> {
        public:
          explicit codecvt_utf8(size_t refs = 0);
          ~codecvt_utf8();
        };
      
        template<class Elem, unsigned long Maxcode = 0x10ffff,
          codecvt_mode Mode = (codecvt_mode)0>
        class codecvt_utf16
          : public codecvt<Elem, char, mbstate_t> {
        public:
          explicit codecvt_utf16(size_t refs = 0);
          ~codecvt_utf16();
        };
      
        template<class Elem, unsigned long Maxcode = 0x10ffff,
          codecvt_mode Mode = (codecvt_mode)0>
        class codecvt_utf8_utf16
          : public codecvt<Elem, char, mbstate_t> {
        public:
          explicit codecvt_utf8_utf16(size_t refs = 0);
          ~codecvt_utf8_utf16();
        };
      }
      


  1. IvanTamerlan
    21.03.2017 19:39

    я тихонько мечтаю о некоторых фичах С++, которые никогда не появятся.
    Что это могло быть?
    1) полноценные модули (видел в обсуждениях)
    2) библиотека модулей (вытекает из первого). сейчас приходится рыскать на просторах интернета и перебирать библиотеки от посторонних авторов на посторонних ресурсах. Хотя в С++20 заявляны, возможно, некоторые классы. Побольше их на все случаи жизни.
    3) функции типа GetHelpFunction(), которая предоставит инфу по функционалу. Желательно, на универсальном языке, понятном человеку. И тут возникает проблема — пока универсального языка не существует, есть варианты костылирования из уже существующих языков, типа того же английского (недостаток — его надо знать заранее и хорошо).

    Поставил сверхсложные задачи (особенно третью). Т.к. я технарь, сложностей не боюсь — уже продумываю решение проблемы. Вариант универсального языка:
    обучение в играх. Там вообще может не использоваться текст, только жесты и демонстрация к чему жест приводит. Чем не универсальный язык? Но он реализуется, скорее, средствами IDE, нежели средствами самого языка программирования. Но при таком подходе от текстового языка программирования можно отказаться (он используется, но не виден пользователю).


    1. RdSpclL
      21.03.2017 20:15

      И тут возникает проблема — пока универсального языка не существует, есть варианты костылирования из уже существующих языков, типа того же английского (недостаток — его надо знать заранее и хорошо).

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

      И еще не совсем понятно, что «хуже»: какие-то знания, или обучение.


    1. Alex_ME
      21.03.2017 22:36
      +5

      Под библиотекой модулей — вы подразумеваете пакетный менеджер, по типу npm, pip, nuget итп? Если да, то я просто мечтаю о такой фиче. Реализуется сейчас частично отдельными независимыми разработчиками инструментов, так, например, в VS есть "NuGet для C++"


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


      На мой взгляд самый логичный вариант — использование метаданных, как в C#, с описанием функции, аргументов итп. На английском.


      1. Pancir
        23.03.2017 11:44

        Я начал сейчас ковырять conan, пока очень доволен, но он еще молод и активно развиваться. https://www.conan.io/


        1. eao197
          23.03.2017 12:10

          Проблема conan-ов, vcpkg, CPM и др. подобных вещей в том, что им требуется централизованный репозиторий пакетов или репозиторий с метаописаниями пакетов. В условиях, когда нет одного доминирующего де-факто стандарта на управление зависимостями это неудобно. Плюс к тому, на Linux-ах разработчики используют зачастую штатные менеджеры пакетов и в сторону внешних инструментов, вроде conan-а или cpm-а смотрят неодобрительно.

          Имхо, удобнее, когда управление зависимостями делается без необходимости куда-то загружать пакет или его описание. Например, когда зависимости разруливаются через ExternalProject_Add в CMake. Но только в более человеческом виде :) Используем нечто подобное уже около года — очень удобно, по крайней мере для подключения OpenSource проектов, которые можно забирать с github, bitbucket или sourceforge.


    1. Scf
      22.03.2017 15:59

      В других языках проблема c документацией решена: javadoc


  1. crea7or
    21.03.2017 20:05

    А всякие ifstream с wstring и раньше же работали?


    1. TargetSan
      21.03.2017 20:14
      +3

      Это было нестандартное расширение в MS STL


      1. agmt
        21.03.2017 23:26
        -2

        А остальным и не нужны недокидорвки, т.к. есть UTF-8


        1. TargetSan
          22.03.2017 10:03

          Проблема в том, что стандарт С++ не говорит о том, в какой кодировке однобайтовые строки. И не говорит, как нижележащее системное АПИ должно их интерпретировать. Современные линуксы используют UTF-8, там всё просто. А Windows использует однобайтовую системную локаль, с непредсказуемым результатом.


  1. JegernOUTT
    21.03.2017 20:16
    +1

    Куча всего по constexpr вводят, даже обсуждают constexpr аллокации в куче. А хорошего метода для отладки шаблонного кода (constexpr кода в чуть меньшей степени) нету, помимо топорного static_assert и type_traits (хорошо, что ещё появился if constexpr).


    Было бы здорово, если бы появилось что-то по типу static_warning. Оно, в сочетании с будущим $reflect (который, насколько я знаю, будет способен вытащить имя типа с присутствующими квалификаторами) могло бы чуточку поспособить отладке и пониманию кода, который разворачивается в момент компиляции.


    1. antoshkka
      21.03.2017 20:17

      Приходите на встречу. Как раз буду рассказывать о планах на constexpr_trace и constexpr_assert для С++20.


      1. Kitmouse
        21.03.2017 22:46
        +1

        запись будет?


        1. antoshkka
          22.03.2017 12:07

          Да. Но не уверен что будет способ задавать вопросы удалённо.


          1. TargetSan
            22.03.2017 12:23

            А можно ли оставлять вопросы на сайте?


            1. antoshkka
              22.03.2017 13:10

              Мне тут nataliamakarova773 подсказала, что «на youtube можно будет задавать вопросы, будем озвучивать докладчикам».


      1. TargetSan
        22.03.2017 12:22
        +2

        Концепты с двусторонними последствиями (т.е. бьют по рукам и вызывающий код, и за непредусмотренный юз в теле ф-ции). Мечты, мечты...


        1. sergegers
          23.03.2017 11:45

          Бьёрн говорил, что пока отказались из-за проблем с совместимостью.


  1. bfDeveloper
    21.03.2017 20:32

    Долго гуглил, но так и не смог понять: какой из вариантов корутин обсуждается? Было два: бустовый и microsoft'овский, и точно были холивары, который лучше и правильнее. Будут у нас слова co_async, co_await или нет?


    1. ZaMaZaN4iK
      21.03.2017 20:37
      +5

      «Гор-рутины» как бы намекают :)


  1. ZaMaZaN4iK
    21.03.2017 20:36
    +1

    Спасибо большое за огромную проделанную Вами работу!

    Вопрос насчёт Number TS: правильно ли я понимаю, что мы будем иметь эффективную длинную арифметику из коробки?


    1. antoshkka
      21.03.2017 20:45
      +1

      Да, но не скоро :(


  1. iroln
    21.03.2017 21:34

    Используете ли вы в компании, или в своих личных проектах, плагины/динамическую-загрузку-библиотек? Опишите в комментариях, какими функциями и классами вы для этого пользуетесь?

    Да, используем. В проекте плагинная система построена на базе CTK Plugin Framework.


  1. ZaMaZaN4iK
    21.03.2017 21:42

    Вопрос насчёт dll: пользуемся и очень активно. Используем для этого WinAPI.


  1. Biga
    21.03.2017 22:05
    +2

    Что-нибудь слышно насчёт интроспекции / рефлексии?


    1. ZaMaZaN4iK
      21.03.2017 22:10

      С рефлекшеном всё сложно, но работы активно ведутся.


      1. neit_kas
        22.03.2017 04:53

        А не знаете, хоть приблизительно, как это реализовать планируют? А то как-то рефлексии и C++ вместе как-то в голове не укладываются.


        1. Satus
          22.03.2017 05:03
          +2

          Это будет compile-time рефлексия. Синтаксис будет сродни шаблонам.


        1. Dark-Energy
          22.03.2017 11:33

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


        1. ZaMaZaN4iK
          22.03.2017 15:16
          +1

          Есть несколько предложений в комитет, причём одно из них достаточно новое. Но базируются они вот на этом решении: https://github.com/matus-chochlik/mirror


  1. vanxant
    21.03.2017 22:48
    +2

    С контрактами всё так же, т.е. никак?


    1. antoshkka
      22.03.2017 11:39
      +2

      На этой встрече обсуждали контракты: одобрили их в EWG, отправили на рассмотрение в LEWG (где скорее всего просто помусолят тему «интеграция контрактов в стандартную библиотеку)», далее отправят в CWG.

      Все шансы что контракты будут в C++20.


  1. NYM
    21.03.2017 23:07
    +4

    Комментарий к опросу
    Да, плагины, динамические библиотеки использовались как в своих, так и в рабочих проектах компаний. Ранее для этого были свои обертки над функциями WinAPI или POSIX. Как правило, это были кроссплатформенные обертки с реализаций под Win/Nix.
    Не так давно в boost все же появилась поддержка динамических библиотек. Теперь использую ее.

    Не по опросу ...
    Возможно эта информация прошла мимо, но как мне могло показаться, в C++17 опять не вошла рефлексия. Эта тема для меня очень интересна. По моему мнению, появление рефлексии в C++ дало бы много возможностей для разработки прикладных библиотек без «костылей», с помощью которых можно было бы сделать компактно сервиализацию, работу с БД (ORM), реализацию RPC и разных REST API.


    1. TargetSan
      22.03.2017 10:08
      +1

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


      1. encyclopedist
        22.03.2017 17:05

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


  1. cranium256
    21.03.2017 23:15
    -5

    Шаблоны — боль. Это как если в России всё делопроизводство велось бы на китайском языке. Или в Китае — на русском. Мозги приходится выворачивать в ортогональную плоскость. Но здесь видимо уже ничего не попишешь. Или шанс есть?


    1. Satus
      22.03.2017 05:05
      +1

      А как вы предлагаете заменить их функционал?


      1. TargetSan
        22.03.2017 10:10
        +1

        Для начала хотелось бы концепты. Причём не лайт, с ограничением только "наружу", но и с ограничением "внутрь".


        1. abikineev
          22.03.2017 17:29

          Вот вам хочется иметь концепты. Так хочется и мне. А люди, жалующиеся на шаблоны, как на что-то сложное и не похожее на С, скорее и концепты проклянут.


          1. TargetSan
            22.03.2017 17:33

            Эмм… они проклянут фичу, которая вместо листинга ошибки инстанцирования на несколько экранов покажет type X does not satisfy concept Y at file.cpp:42?


            1. abikineev
              22.03.2017 17:40
              +1

              они пойдут в file.cpp:42 и далее
              "что за е… т requires Y< X >? Почему не void*?"


              1. TargetSan
                24.03.2017 13:28

                Тогда они выбрали не тот язык.


  1. dendron
    21.03.2017 23:59
    -4

    ИМХО, скучно и мелко.

    Я бы хотел доработок по части SIMD и выровненных данных (до сих пор какие-то танцы с бубном). Ещё доработанные корутины, а не то что сейчас есть (лучше пусть просто дадут стандартизированный способ сохранить стэк, дальше сами разберёмся).

    Новые форматы для чисел кому-нибудь пригодятся, но очередной контейнер со скрытыми аллокациями — гадость. Хватит лепить из C++ подобие Java! Уже столько наплодили вредных сущностей для «программистов на пол-ставки» из разряда «лепи не думая, рантайм сам с памятью разберётся». std::string, std::vector, std::function… Теперь у нас даже числовые типы будут память выделять!

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


    1. Satus
      22.03.2017 05:06
      +4

      std::string, std::vector, std::function…
      Чем же они непредсказуемы?


      1. dendron
        22.03.2017 23:11
        -2

        vec.push_back(a);

        Вы сможете сказать, будет тут выделена память или нет? Не сможете, потому что это а) зависит от внутреннего состояния vec б) зависит от конкретной стратегии std:vector на данной платформе.

        Это нормально в языках со сборкой мусора, но неприемлимо в языках с «ручным» управлением памятью. Править такой код от юных (или не очень) падаванов делающий аллокации на каждый чих — удовольствие ниже среднего. И чем дальше, тем больше становится способов вызвать скрытое выделение памяти. Тот же std::function соединённый с std::bind и вроде как невинным ссылочным типом превращается… правильно, в ещё больше аллокаций.

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


        1. Satus
          22.03.2017 23:35
          +4

          Вы сможете сказать, будет тут выделена память или нет?
          Ну вообще-то могу. Я могу проверить, если capacity меньше, чем размер вектора, тогда выделения памяти не будет.
          зависит от конкретной стратегии std:vector на данной платформе.
          Стратегия одна — расширять вектор, когда capacity > size. Меняться может только множитель роста, хотя на практике все популярные компиляторы используют одну и ту же стратегию.
          Вы также можете контролировать выделение памяти, подсунув свой аллокатор. Или же просто зарезервировать вектором нужное кол-во элементов.
          Править такой код от юных (или не очень) падаванов делающий аллокации на каждый чих — удовольствие ниже среднего.
          Юные падаваны обычно не пишут код, в котором узкое место в производительности — стратегия выделения вектором памяти. Да и неопытный программист наделает гораздо больше ошибок, когда будет пытаться сделать собственный аналог динамически расширяемого контейнера. Это не аргумент.
          std::function соединённый с std::bind
          То, как std::bind хранит свои данные, описано довольно неплохо на cppreference. Да и с С++14 использовать std::bind смысла особого нет, его заменили лямбды, которые оптимизируется компилятором гораздо лучше.

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


          1. dendron
            24.03.2017 01:13
            -3

            >Ну вообще-то могу. Я могу проверить, если capacity меньше, чем размер вектора, тогда выделения памяти не будет.

            Не пердёргивайте, вопрос был без написания кода. Вы всерьёз полагали что мне неизвестно как программным способом узнать состояние std:vector?

            Вы смотрите в код и видите такую строчку. Будет ли выделена память? А фиг его знает, надо (как вы сами сказали) ковырять состояние объекта на этот момент.

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

            У меня не было бы претензий к std::vector если бы его не сделали «дуракаустойчивым». То есть если бы push_back() при нехватке места вызывал бы падение, а все места выделения были бы обозначены вызовами resize(). Но нееет, у нас же тут типа Java, всё должно быть «удобно» и «автоматически», чтобы даже хреновый код от студентов-первокурсников мог как-то работать.


            1. Satus
              24.03.2017 02:22
              +3

              Вы смотрите в код и видите такую строчку. Будет ли выделена память?
              Если я зарезервировал память, то я точно знаю, что не будет. Если же мне достаточно того, что я знаю, что вектор выделит память когда понадобится, почему его не использовать?
              Если вы напишете свой аналог динамически расширяемого массива, вы всё равно не сможете сказать, будет ли выделена память в этой строчке, так как это будет зависеть в большинстве случаев от введенных пользователем данных или иных неизвестных на этапе компиляции переменных.
              Нужно глядя на строчку всегда (как вы сами сказали) точно знать когда будет происходить выделение памяти.
              int i;
              cin << n;
              auto buffer = new char[n];
              
              Сколько будет выделено памяти? Вы не знаете. И я не знаю. Для этого и сделаны структуры данных, которые выделяют память по требованию.
              То есть если бы push_back() при нехватке места вызывал бы падение
              Это идёт против самого определения структуры данных «вектор». Вы путаете вектор (не std::vector, а структура данных «вектор») с обычным массивом.
              а все места выделения были бы обозначены вызовами resize().
              Тогда вам пришлось бы при каждой вставке проверять размер и кол-во текущих элементов. В таком случае проще просто использовать обычный массив.


              1. dendron
                24.03.2017 08:44

                >Сколько будет выделено памяти? Вы не знаете. И я не знаю. Для этого и сделаны структуры данных, которые выделяют память по требованию.

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

                >Это идёт против самого определения структуры данных «вектор». Вы путаете вектор (не std::vector, а структура данных «вектор») с обычным массивом.
                Ничего я не путаю. Вы бы по-прежнему смогли изменять размер массива как и раньше.

                >Тогда вам пришлось бы при каждой вставке проверять размер и кол-во текущих элементов. В таком случае проще просто использовать обычный массив.

                Это и так происходит каждый раз при push_back(), просто скрытно от программиста. В моём варианте программист бы сам проверял выделенный размер когда ему нужно.

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


                1. Antervis
                  24.03.2017 09:06
                  +2

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

                  Далеко не всегда выделение памяти — узкое место в программе. А там, где это действительно боттлнек (и профайлер показал вам на это), никто не мешает вам:
                  а. использовать собственные аллокаторы
                  б. резервировать память вручную
                  в. пользоваться обычным массивом (или std::array)
                  г. не пользоваться компонентами, аллоцирующими в куче
                  Но не для C++, где фишкой языка является предсказуемость, из которой следует полная ответственность программиста за ход выполнения своей программы.

                  А что, соответствующие стандарту классы как-то непредсказуемо себя ведут? Полный контроль, как я уже упомянул, имеет смысл только по результатам работы профайлера. Иначе можно год писать то, что делается за 2-3 недели


                1. Satus
                  24.03.2017 14:01
                  +1

                  Опять передёргиваете, вопрос был не о количестве выделенной памяти, а о самом факте выделения.
                  Окей. Есть у вас своя deque с размеров блока в n байт. Вы говорите ей зарезервировать m элементов, причём значение m вы не знаете. Сколько блоков памяти будет выделено?
                  Ничего я не путаю. Вы бы по-прежнему смогли изменять размер массива как и раньше.
                  Это будет уже не вектор. Это всё равно что жаловаться, что двусвязный список хранит указатель назад, когда вам нужно только вперёд: если убрать указатель назад, это уже будет не двусвязный список по определению.
                  В моём варианте программист бы сам проверял выделенный размер когда ему нужно.
                  Ваш вариант неудобен и не нужен никому кроме вас. Если вам нужен контроль, делайте как написал Antervis.
                  Именно практика «не нужно думать о выделении памяти, умные дяди всё придумали за нас, будем просто лепить код» являтся порочной для C++.
                  В программах, где выделение памяти — узкое место, вам всё равно придётся вручную это контролировать. Никто не забирает у вас возможность контролировать память.


            1. MikailBag
              24.03.2017 19:12

              А что вы предлагаете?
              Писать


              if(vec.size()==vec.capacity()){
                  vec.resize(vec.size()*2);
              }
              vec.push_back(a);

              вместо


              vec.push_back(a);

              ?
              Вы в любом случае не сможете проконтролировать выделение памяти, если, скажем, это web-сервер.


        1. antoshkka
          24.03.2017 11:40
          +3

          vec.push_back(a);

          Вы сможете сказать, будет тут выделена память или нет? Не сможете, потому что это а) зависит от внутреннего состояния vec б) зависит от конкретной стратегии std:vector на данной платформе.

          Если нужно чтобы элементы хранились непрерывно и:
          * если вы точно знаете, сколько элементов вам нужно — используйте array/stack_vector
          * если вы знаете, сколько в среднем хранится элементов — используйте small_vector/vector+reserve
          * если не знаете — используйте vector

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

          Если это не так — опишите пожалуйста поподробнее вашу идею и вашу реализацию контейнера.


  1. quwy
    22.03.2017 00:37
    +1

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

    Пропасть между профессионалом и новичком-хеловордщиком уже шириной в световой год. Или это и есть основная цель?


    1. Psionic
      22.03.2017 04:09
      +1

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


    1. Deosis
      22.03.2017 06:58
      +1

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


      1. Duduka
        22.03.2017 08:03
        -2

        Здесь проблема в многоязычии, нет больше языка сопоставимого по функциональности и выразительности с #cplusplus, а остальные языки реализуют, по своей сути, подмножество, и если кто-то хочет понять программу другого, то приходится менять мировоззрение и методику программирования под соответствующий язык, а в случае #cplusplus еще и понимать как эти трюки реализуются в другом(их) языке(ах), или использовать общее подмножество, что делает программирование на низкоуровневом языке, как минимум, сомнительным занятием.


    1. antoshkka
      22.03.2017 09:10
      +2

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

      Посмотрите на код практически любых контейнеров Java, C#, C (где контейнеры через макросы) или Rust.


      1. PsyHaSTe
        24.03.2017 19:31

        @antoshkka А что с C#? Имхо 99% всей сложности языка из-за макросов существуют. А шарп 2.0 от шарпа 7.0 для пользователя отличается только незначительным сахаром. Ну там, свойства можно инициализировать не в конструкторе, а прямо при объявлении, да экстеншн-методы пописывать… Самое сложное, что есть в языке — yield и async/await, ни в какое сравнение со сложностями плюсов не идет. Да, системы усложняются, появляются фреймворки, все такое… Но сама база не меняется никогда. И это очень серьезно ограничивает сложность: нетрудно разобраться с любым бизнес-фреймворком, если каждый элемент по-отдельности понятен и не изменился с момента академической юности.


        1. antoshkka
          26.03.2017 13:04
          +2

          А шарп 2.0 от шарпа 7.0 для пользователя отличается только незначительным сахаром.


          Кортежы, именованные поля кортежей, structured bindings, шаблоны с is, шаблонные switch… Это только некоторые нововведения 7 C#. Когда я заглядывал в код контейнеров 5 лет назад — множество ключевых слов C# я просто не знал, т.к. большинство пользователей их не пишут в повседневном коде и в институте за год их не успели объяснить.

          Написать знакомому программу на C# было адом — абсолютно непонятны времена жизни объектов в лямбдах, примитивы синхронизации немного отличаются, и их приходится учить заново…

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


          1. PsyHaSTe
            26.03.2017 19:14
            -1

            И все это — сахар. Именованные кортежи — чтобы не писать класс для внутренних нужд, используется очень редко (по крайней мере у нас за использование таплов в публичном апишном интерфейсе обижают ногами), is довольно бесполезная фигня и опять же — сахар, шаблонные switch — да, новая и полезная фишка, но даже не зная их устройства увидев в первый раз в жизни код с их использованием можно сразу понять, что происходит и как это работает.


            Когда я заглядывал в код контейнеров 5 лет назад — множество ключевых слов C# я просто не знал, т.к. большинство пользователей их не пишут в повседневном коде и в институте за год их не успели объяснить.

            Честно говоря, не представляю, какие страшные ключевые слова могли там встретить — public/readonly/get/static? Я брал за отсчет C# 2.0 как по факту первый используемый в повседневном использовании. Так вот, с тех пор (то есть более чем за 10 лет) в языке появились ключевые слова var/dynamic/nameof, и собственно всё. Ну еще linq-синтаксис которым никто не пользуются, сюда эти where/let, но они контекстные и как я уже сказал — неиспользуемые.


            Все изменения языка, как и его структуру, можно изучить ну за 2-3 недели точно. После чего можно 10 лет на шарпе не писать, а потом вернуться и продолжить с того момента, где остановился.


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

            Да. Вывод верный. Только вот вопрос не в том, сложен ли язык, если ты его не знаешь, а в том, насколько легко выучить язык и поддерживать знание на определенном уровне. Я вот например уверен, что шарп я — знаю. Да, я могу не знать какие-то тонкости работы стандартных классов, могу не ответить сходу на вопрос "как сделать так, чтобы вызвались 3 разных перегрузки" или еще что-нибудь в таком роде, но в целом язык — извините, но да, знаю. В тех же плюсах людей которые могут с уверенностью сказать, что знают язык — нет в принципе. Не потому, что язык сложный, а потому что макросы позволяют его менять. И поэтому если я вижу в шарпе if я ЗНАЮ, что дальше будет открывающая скобка, условие, и закрывающая скобка). В то время как на макросах можно спокойно спрятать те же скобки в этот самый макрос и получить такой вот "руби-стайл".


            Это я и написал, сложность плюсов в том, что под этим названием скрывается целый класс мета-языков, и код одного "плюсовика" будет совершенно непонятен другому. С шарпами и прочими строгими языками такое невозможно. Поэтому я и хотел узнать, в чем сложность шарпа? У него немного ключевых слов, у него нет макросов, которые могли бы поменять структуру программы, раз в 2-3 года добавляется немного сахара, которые в 99% случаев интуитивно понятны (за исключением, может быть, async/await), и я просто не вижу того, что может создавать сложность. Потому что озвученные проблемы "абсолютно непонятны времена жизни объектов в лямбдах, примитивы синхронизации немного отличаются" просто от непонимания того, что в языке с GC эти вопросы неважны в общем случае и отданы на откуп компилятору, но ведь это концепция языка. Эта концепция не меняется никогда и узнав её один раз, она остается с тобой до конца жизни языка.


            1. PsyHaSTe
              26.03.2017 19:21
              -1

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


            1. eao197
              26.03.2017 20:35

              Ну, OK. Допустим, что вы правы в оценке проблем C++. Выход из этой ситуации в чем?


              1. PsyHaSTe
                26.03.2017 21:14
                +1

                Так я и не обещал выход, я отвечал на


                Посмотрите на код практически любых контейнеров Java, C#, C (где контейнеры через макросы) или Rust.
                Что это попросту не так. Ну а сточки зрения языка тут ничего не сделать, джинн выпущен из бутылки. Точно так же, как легаси в виде winapi-интерфейсов, как легаси в виде текстового обмена в *nix, как legacy-коллекции в C# (до выхода дженериков в 2.0). Я лично не клялся в верности ни одному языку программирования. И переход с С++ на тот же раст должен быть достаточно простым. Да, там есть новые концепции, которые надо выучить, но чем больше язык построен на концепциях (они же абстракции), а не на конкретной имплементации/стандартной либе/этц, тем проще им пользоваться, потому что знания не пропадают, а аккумулируются и синергируют.

                Так что, хотя я и не собирался, но все же отвечу: для С++ как языка выхода особого нет, кроме как на уровне каких-то гайдлайнов запрещать пользоваться каким-то подмножеством языка. Но это не поможет понять ошибку в стандартных классах или неправильном их использовании. С точки зрения С++-программистов выход есть и еще какой — тот же Rust это и есть C++, в котором смартпойнтеры на уровень языка добавили да решили попытаться сделать автоматическую управляемую детерменированную работу с памятью вместо new/delete. Так сказать, зачем нам С++ из которого мы гайдлайнами вырежем плохой функционал, если можно получить всё на блюдечке вместе с нормальным пакетным менеджером, приятными ништяками вроде паттерн матчинга…


                1. eao197
                  26.03.2017 21:44
                  +2

                  Так я и не обещал выход

                  Так а никто и не сказал, что ваш диагноз верен и что вы, действительно, правы ;)
                  С точки зрения С++-программистов выход есть и еще какой — тот же Rust это и есть C++

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

                  С++ сильно продвинулся в этом направлении. Даже если брать более короткий временной интервал после 2003-го года, то в языке появилось больше средств для безопасной работы:
                  * auto для вывода типа переменных (устраняют ошибки вроде int l = strlen(s));
                  * range-for (нет целого класса ошибок с выходом за рамки массивов из-за плюс-минус единички);
                  * лямбды (делают удобным использование стандартных алгоритмов вместо ручных циклов, которые были источниками ошибок);
                  * variadic templates (сильно уменьшают надобность в макросах);
                  * rvalue references и move-semantic (сильно упрощают, например, прием и возврат «тяжелых» значений);
                  * std::array вместо C-шных массивов;
                  * std::unique_ptr (исправляет косяки std::auto_ptr);
                  * auto для вывода типа возвращаемых значений и типов в полиморфных лямбдах (опять же уменьшают надобность в макросах).

                  Если плотно сидишь на C++11/14, а потом внезапно возвращаещься в рамки C++98/03, то очень быстро выясняешь, насколько сильно упростился язык в повседневном применении.

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

                  когда на C++ пишут софт для микроконтроллеров, драйвера и куски ядер ОС, бортовое ПО, СУБД, сложные десктоп-приложения, кросс-платформенные мобильные приложения (целиком или частично), компиляторы и виртуальные машины для языков программирования, игры, ресурсоемкие расчеты и т.д., то вполне естественно, что в каждой из этих ниш используется свое подмножество C++. Так что тот факт, что C++ очень разный — это еще один фактор, который влияет на то, как быстро и в какую сторону (в какие стороны) язык развивается.


                  1. PsyHaSTe
                    27.03.2017 00:03

                    Никаких диагнозов, я отвечал на конкретную цитату :) Не более того. Остальное — мои размышления, я никого не призываю с ними соглашаться, просто такое вот мое мнение.


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

                    С++ сильно продвинулся в этом направлении. Даже если брать более короткий временной интервал после 2003-го года, то в языке появилось больше средств для безопасной работы:

                    Я не прошу прекращать работу комитета. Просто сейчас С++ из локомотива инноваций превратился в догоняющий язык (когда уже будет фича А, когда уже будет фича Б, ...). Это не плохо и не хорошо, просто естественный процесс. А комитет упрощает боль разработчикам, которым нужно поддерживать легаси С++ (опять же имхо). Возвращаться на старую версию языка всегда неприятно, тут что С++, что не С++, разницы не вижу. Что он развивается — это очевидно, вопрос в том, сколько в нем изначально фатальных недостатков. Кто-то в них признается, кто-то предпочитает не замечать, но рано или поздно новый язык становится настолько хорош, что люди пересиливают свою инертность и начинают миграцию. Так было с С, так было с С++, так было с джавой/коболом/..., так в ближайшее время будет а растом или еще каким-нибудь еще "более лучшим" языком. Стоит ли от этого печалиться? Вряд ли, учитывая, что все языки разиваются, а переход на другой возможен только когда он прям ваще вкусный. А это значит — меньше боли нам, разработчикам.


                    1. eao197
                      27.03.2017 08:26

                      просто такое вот мое мнение
                      Ну так применительно к статье про новый стандарт C++ и про предложения для следующего стандарта кроме констатации «все пропало» хотелось бы услышать какие-то идеи «по спасению». Если идея в том, что «пора валить» на Rust, ну OK.
                      Просто сейчас С++ из локомотива инноваций превратился в догоняющий язык
                      Просто интересно, когда это C++ был «локомотивом инноваций»?
                      новый язык становится настолько хорош, что люди пересиливают свою инертность и начинают миграцию. Так было с С, так было с С++, так было с джавой/коболом/...
                      Боюсь вас огорчить, но и C, и C++, и Java и даже COBOL продолжают активнейшим образом использоваться.


                      1. PsyHaSTe
                        27.03.2017 16:08

                        Просто интересно, когда это C++ был «локомотивом инноваций»?

                        Когда он появился. Можно долго рассуждать на тему, что в Smalltalk'е это было за миллион лет до плюсов, остальные идеи были взяты тоже откуда-то еще, но скомпоновалось это весьма удачно именно в плюсах. И последующее их развитие, темплейты и вот это все — это и было отличное развитие.


                        Боюсь вас огорчить, но и C, и C++, и Java и даже COBOL продолжают активнейшим образом использоваться.

                        Смотря что мы имеем ввиду под "использованием". А так-то и на whitespace люди что-то пишут. По крайней мере про кобол мне страшно даже думать, что кто-то на нем еще пишет.


                        1. eao197
                          27.03.2017 16:23

                          Можно долго рассуждать на тему, что в Smalltalk'е это было за миллион лет до плюсов, остальные идеи были взяты тоже откуда-то еще, но скомпоновалось это весьма удачно именно в плюсах.
                          Вы прям заинтриговали. Что именно из C++ было в Smalltalk-е задолго до того как? А то я, например, все еще нахожусь под впечатлением, что C++ позаимствовал многое из Simula, ML и Ada, но отнюдь не из Smalltalk.
                          Смотря что мы имеем ввиду под «использованием».
                          Наличие business-critical приложений, прекращение работы которых станет заметным для большого количества людей. Которые нуждаются в поддержке и развитии, и которые не могут по каким-то причинам быть переписаны на более современных языках программирования.
                          По крайней мере про кобол мне страшно даже думать, что кто-то на нем еще пишет.
                          А вы наберитесь смелости, представьте себе такое. Может категоричности по отношению к тому же C++ станет поменьше.


                          1. PsyHaSTe
                            28.03.2017 12:21

                            Вы прям заинтриговали. Что именно из C++ было в Smalltalk-е задолго до того как? А то я, например, все еще нахожусь под впечатлением, что C++ позаимствовал многое из Simula, ML и Ada, но отнюдь не из Smalltalk.

                            Мне казалось, ответ очевиден.


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

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


                            1. eao197
                              28.03.2017 12:31

                              Мне казалось, ответ очевиден.

                              Мне кажется, вы в очередной раз ошибаетесь. Если для вас «очевидный ответ» — это ООП, то C++ позаимствовал ООП из Simula, а не из Smalltalk. Тут можно еще много чего наговорить про различия между ООП для статически типизированных ЯП и для динамически типизированных, а так же о том, почему Smalltalk имеет совсем косвенное отношение к ООП для статически-типизированных языков, а так же почему Smalltalk считают «родителем» ООП не смотря на то, что та же Simula появилась гораздо раньше. Но это здесь явно офтоп.
                              Ну, так можно хоть аду считать живым ЯП.

                              Ладно бы вы COBOL отказывались признавать живым. Но назвать Ada мертворожденной… Это сильно. От человека с таким кругозором критика C++ начинает играть новыми красками.


                              1. PsyHaSTe
                                28.03.2017 12:38

                                ADA не мертворожденная (в отличие от многих других), но считать её в 2017 году используемым яп я не собираюсь. Хотя по вашему определению она скорее весьма популярна.


                                1. eao197
                                  28.03.2017 12:51
                                  +1

                                  Жизнеспособность, востребованность, используемость и, уж тем более, популярность — это все слабосвязанные друг с другом вещи. Ada вполне себе живой язык, востребованный и используемый, развивающийся (последняя версия стандарта от 2012-го года), с регулярно обновляющимися инструментами для разработки. То, что это не попадает в поле вашего зрения, не меняет объективного положения дел.

                                  У вас и по поводу C++ какое-то избирательное суждение: чего не видите, того не существует, что не популярно, то не жизнеспособно. Отсюда и выводы о том, насколько хреново все в C++ и что поэтому C++ники должны искать выход в Rust-е (как до этого в C#, а еще до этого в Java, а еще до этого в Delphi, а еще до этого в Eiffel, ...). Остается только порадоваться, что C++ развивается не смотря на мнение таких судильщиков. Ибо вы явно даже отдаленно не представляете себе, сколько кода на C++ уже написано, как долго он будет использоваться и развиваться, и сколько еще на C++ напишут до того, как тот же Rust перейдет в категорию действительно широко используемого инструмента.


                                  1. PsyHaSTe
                                    28.03.2017 14:58
                                    -1

                                    Спор ни о чем. Просто у людей закостенелое отношение. Вот писал он на плюсах 10 лет, человеку уже не интересно изучать что там за монады или higher kinded polymorphism, ему бы auto и модульность получить — уже неплохо. А это определяет рынок программистов, из которых и выбирают компании. Допустим тот же раст сейчас молод, допустим через 3 года он победит все детские болезни. Итого в 2020 году не будет ни одной причины начинать новый проект на плюсах, потому что раст ничем не хуже, во многом — лучше, а весь пласт уже существующего кода просто подключается через кросс-языковые механизмы. Но люди будут их делать. Почему? А просто из-за костности мышления. Своё старое привычное болото всегда лучше. Типичный парадокс блаба.


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


                                    Ada вполне себе живой язык, востребованный и используемый, развивающийся (последняя версия стандарта от 2012-го года)

                                    Мы ведь уже выяснили, что понятия "востребованный" и "живой" — различаются для нас. Для меня например живой язык имеет хотя бы 1% вакансий на площадках вроде hh.ru, все остальные — эзотерика и история.


                                    1. eao197
                                      28.03.2017 15:05

                                      Типичный парадокс блаба.

                                      При таком уровне аргументации остается только спросить: сколько вам лет?

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


                                      1. PsyHaSTe
                                        28.03.2017 15:14

                                        А что не так с уровнем? Я расписал все: есть язык Х (не обязательно плюсы, абсолютно любой), если есть язык У который ничем не хуже и позволяет прозрачно переиспользовать функционал Х, то смысла писать на Х нет никакого. Я не понимаю этой клятвы оставаться с языком Х пока он не почит на смертном одре. Какая разница, сколько на нем софта написано для разработчика, который делает новый проект? Да никакой.


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


                                        1. eao197
                                          28.03.2017 15:26

                                          А что не так с уровнем?

                                          Например, продемонстрированное ранее отсутствие кругозора, категоричность и максимализм. А так же откровенные заблуждения.
                                          Я расписал все: есть язык Х (не обязательно плюсы, абсолютно любой), если есть язык У который ничем не хуже и позволяет прозрачно переиспользовать функционал Х, то смысла писать на Х нет никакого.

                                          Вы забываете о существующих наработках и разработках. Если для языка X есть мегабиблиотека, которая позволяет за пару рабочих дней (а то и часов) собрать решение под какую-то типовую задачу с немного различающимися условиями, то языком X будут продолжать пользоваться даже после того, как аналог появится на языке Y. Хотя появление этого самого аналога — это еще большой вопрос.
                                          Например, появление хороших вычислительных библиотек на C++ отнюдь не мешает продолжать использовать Fortran на серьезных вычислительных задачах. А наличие для C++ того же Eigen-а отдаляет пришествие Rust-а в эту нишу на неопределенное время.
                                          C++ мог бы использоваться в разработке ОС даже на самом низком уровне, т.к. позволяет практически тоже самое, что и С. Тем не менее, ядра Linux и FreeBSD как разрабатывались на C, так и продолжат разрабатываться. И заменить C, который еще более древний и убогий, чем C++, Rust-у здесь так просто не получится.
                                          Изначально речь шла вообще о другом, а именно о том, что и шарпы, и остальные перечисленные языки намного проще в изучении, чем плюсы.
                                          Так а какой практический вывод из этого? Бросить заниматься C++ и уйти всем на более молодые языки, при проектировании которых использовался опыт того же C++?
                                          Ваша проблема в том, что вы считаете такой уход не просто разумным, но и неизбежным. А для многих текущих C++ проектов это совсем не так.


                                          1. PsyHaSTe
                                            28.03.2017 17:44
                                            -1

                                            Для многих — не так, а для многих — так. Каждый решает сам, что ему приятнее — использовать более удобные абстракции и потратить время на интеграцию с существующим кодом или тратить по чуть-чуть каждый при использовании выбранного ЯП. Я считаю, что первый вариант лучше не только в плане экономии в долгосрочной перспективе, но и больше отвечает потребностям разработчика (делать однотипную необременяющую работу vs написание скрипта для автоматической работы, скрипт сложнее, но написанный однажды выручает до конца).


                                        1. DarkEld3r
                                          28.03.2017 15:28
                                          +1

                                          если есть язык У который ничем не хуже и позволяет прозрачно переиспользовать функционал Х

                                          Это не справедливо для Y = Rust и X = C++. Ну или надо уточнить, что подразумевается под "свободно переиспользовать функционал".


                                          1. PsyHaSTe
                                            28.03.2017 17:46

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


                                    1. DarkEld3r
                                      28.03.2017 15:14
                                      +3

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

                                      Это не так уж просто и удобно.


                                      И даже если исключить этот пункт, то я не уверен, что Rust так уж во всём лучше плюсов. Опять же, "побеждение детских болезней" зависит, в том числе, от популярности и разорвать этот круг удаётся не всем языкам. Если что говорю как человек, которoму удалось найти работу на расте (хвастаюсь), так что не надо про парадокс блаба. (:


                                      1. PsyHaSTe
                                        28.03.2017 15:16

                                        Я выше написал, работа зависит от разработчиков на рынке. Если лид хочет вести его на расте, но на рынке полтора разработчика на нем, ему нафиг не нужны такие автобусные риски, лучше взять что-то более приземленное и проверенное временем. А наличие таких разработчиков зависит от того, застряли ли они на своем уровне или в свободное время повышают квалификацию — ездят по конференциям, изучают новые ЯП и так далее.


                                    1. Antervis
                                      28.03.2017 15:29

                                      Допустим тот же раст сейчас молод, допустим через 3 года он победит все детские болезни

                                      вы хотите сказать, что за 3 года раст достигнет большего, чем с++ за 40 лет?
                                      а весь пласт уже существующего кода просто подключается через кросс-языковые механизмы

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


                                      1. PsyHaSTe
                                        28.03.2017 17:49

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


                                        вы хотите сказать, что за 3 года раст достигнет большего, чем с++ за 40 лет?

                                        Раст уже давно появился — раз. Экспоненциальный рост технологий никто не отменял — два.


    1. mihaild
      22.03.2017 15:43
      +1

      ИМХО с С++11 код во многих местах стал понятнее. range-based for и auto вместо страшных итераторов, using вместо typename упрощают жизнь новичкам.

      move-семантика, конечно, усложняет, но читать ее всё равно относительно просто.


    1. eao197
      24.03.2017 11:53
      +3

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

      Если же сразу учить C++, без отсылок на C, то все гораздо проще. Когда людей учат сразу использовать std::array или std::vector вместо старых массивов, когда range-for или std::for_each+лямбда используются вместо старых for(i=0;i<ASIZE(a);++i), когда из функции возвращается std::pair<bool,std::string> вместо возврата отдельно bool-а и отдельно вручную аллоцированной строки через out-параметр и т.д., и т.п., то современный C++ осваивается гораздо легче, чем тот же C++98/03.


  1. agmt
    22.03.2017 00:43

    Хочется, чтобы язык поощрял (не знаю, как лучше назвать) говнокодпрототипирование. Я восхищаюсь красотой и изящностью C++, который впитывал модные веяния на протяжении десятков лет развития. Но написать прототип быстрее на чём-нибудь другом, где можно

    [line.rstrip('\n') for line in open('filename')]
    , где класс уже содержит методы почти на все случаи жизни. Qt, мне кажется, движется в этом направлении.
    Да, это, быть может, не про сам язык, а библиотеки, но язык задаёт направление, собирает определённую группу людей вокруг себя. И если язык не разрешает std::list::operator[], т.к. он будет провоцировать людей на медленные действия, а предлагает писать std::advance(std::list::begin(), 5), то и либы будут писаться такие же «универсальные», но долго дорабатываемые напильником.


    1. Deosis
      22.03.2017 07:04

      И если язык не разрешает std::list::operator[], т.к. он будет провоцировать людей на медленные действия
      Было бы здорово в таком случае использовать условные директивы:
      #define I_WANT_TO_USE_SLOW_METHODS
      

      Как с unsafe в C# программист берет на себя ответственность за использование такого кода


      1. allter
        22.03.2017 10:04
        +1

        Ещё никто не мешает написать классы-обёртки для внутреннего использования. В принципе, наверное, там и варнинги можно как-то выводить, что мол, пофиксите прототип. :)

        Но по факту, времени на кардинальную переработку алгоритма после написания — как правило, не бывает.


    1. erosinka
      22.03.2017 12:55

      Я не знаю, правильно ли это, но у меня создалось впечатление, что довольно часто принято писать прототипы на чем-то простом, чтобы быстро сделать черновик (Matlab, Julia, Python в конце концов), а потом уже писать чистый код на С++.


  1. devalone
    22.03.2017 03:27
    +5

    А я так надеялся, что модули будут :(


    1. antoshkka
      22.03.2017 12:00

      Мы в РГ21 тоже надеялись и голосовали за их принятие на заседании. К несчастью, к консенсусу на заседании не пришли.


    1. sborisov
      22.03.2017 13:10

      Да, было бы необычно, но очень уж многообещающе выглядело, главным образом скорость компиляции выросла бы. Жаль что не попали в С++17.


  1. elapidae
    22.03.2017 03:28
    +1

    Огромное спасибо за вашу работу, очень люблю плюсы.

    Используете ли вы в компании, или в своих личных проектах, классы способные хранить числа произвольной длинны (unbounded integers) с нестандартными аллокаторами?

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

    Остальные задачи потрясают своей колоссальностью, но очень бы хотелось примитивную рефлексию enum и enum class.
    Пример:
    enum SomeState {
        Undefined = -1,
        AllOk = 1,
        SomeStrange1,
        SomeStrange2,
        ...
    };
    ...
    // Неинициализированное состояние -- какое угодно, хотелось бы 
    // что-то вроде "Undefined = -1: default", тем более слово default зарезервировано, 
    // в основном, для перечислений.
        SomeState s;
        std::cout << s << std::endl; // неизвестно что выведет
    
    // Вывод значения сейчас:
        if (s != AllOk)
            std::cout << "Not correct state: " << s << std::endl;
        // Выведет "Not correct state: 2"
    // Хотелось бы:
        if (s != AllOk)
            std::cout << "Not correct state: " << std::enum_to_string(s) << std::endl;
        // Пусть выводитдет "Not correct state: SomeStrange1"
    ...
    // Чтение из бинарного потока:
        ostream >> s; // если прочитано что-то, не то, в переменной будет мусор.
    // Хотелось бы:
        try
        {
            ostream >> s; // если прочитано что-то, не то, бросается исключение.
        }
        catch (const std::enum_exception &e)
        {...}
    ...
    // Как следствие предыдущего, кастовать:
        SomeState s;
        int sint = 10;
        try
        {
            s = enum_cast<SomeState>(sint);
        }
        catch (const std::enum_exception &)
        {....}
    
    


    Надо на уровне компилятора, стандатрной библиотеки держать:
        T enum_cast<T>();
        class std::enum_exception;
        если совсем расслабиться :default  на к-л значение в перечислении.
    


    P.S. часто слышу, что плюсы не те, так как /нет сборщика/устаревший/не следит за памятью/over 9000 причин/. Считаю, что Стандарт работает как эталон для всех остальных.


    1. monah_tuk
      22.03.2017 09:52

      // Неинициализированное состояние -- какое угодно, хотелось бы
      SomeState s;

      не согласен с таким синтаксисом: пусть будет выведен мусор, что угодно и как угодно — это только объявление, на него может даже процессорная команда не потребуется, а инициализация — это уже дополнительные телодвижения, но ваше предложение с default при таком раскладе:


      SomeState s{};

      уже имеет смысл, что бы там оказалось SomeState::Undefined. Так как, по идее, сейчас там будет 0, но такого элемента в перечислении нет: http://ideone.com/XehYqs


  1. Antervis
    22.03.2017 06:09
    +2

    constexpr аллокацию «в куче»

    Ждем, надеемся, верим
    Используете ли вы в компании, или в своих личных проектах, плагины/динамическую-загрузку-библиотек? Опишите в комментариях, какими функциями и классами вы для этого пользуетесь?

    QPluginLoader.


    1. FadeToBlack
      22.03.2017 06:18

      Достаточно будет и кроссплатформенной QLibrary


      1. Antervis
        22.03.2017 06:30
        +1

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


  1. red1ynx
    22.03.2017 07:30

    Никогда не понимал, зачем std тянуть в стандарт языка. Язык отдельно — либы отдельно. Тот же самый пример с std::optional должен был решиться на уровне баг-фикса, а не через создание комиссии.
    И так смотрю версия C++14 занимает почти 1400 страниц.


  1. AstarothAst
    22.03.2017 09:56
    +7

    operator<=>()

    Оператор «хрен знает», судя по виду :)


    1. marapper
      22.03.2017 10:43
      +2

      spaceship. Выглядит так же.


    1. TargetSan
      22.03.2017 12:27

      Такими темпами скоро будет arbitrary operator definition. a #$^ b >>= c ^&* d.


    1. hdfan2
      22.03.2017 14:16
      +7

      operator?\_(?)_/?()


  1. sborisov
    22.03.2017 10:21
    +2

    Чем дальше С++ развивается, тем больше мне начинает нравиться plain C.


  1. RinWorld
    22.03.2017 11:34

    // P.S.: В примерах выше занк '=' тоже можно не писать :)

    мелкая описка :)

    Будем ждать больше вкусностей в следующем обновлении :)


  1. Gorthauer87
    22.03.2017 11:36
    +2

    Не дождался я светлого будущего и ушел на Rust. Как-то мне кажется, что после С++14 плюсы куда-то не туда пошли. Если С++11 был прорывом, то дальше пошла стагнация и конца ей не видно.


    1. DarkEld3r
      22.03.2017 12:04
      +1

      Немного не согласен со стагнацией: всё-таки C++11 весьма долго принимали и прорывом он казался, по сути, на фоне предыдущего "отсутствия развития". Думаю, что ещё не все процессы устаканились и потом комитет будет работать эффективнее. Опять же, бесконечно "революционные" фичи выдавать не реально. Когда-нибудь дело дойдёт и до модулей и т.д.


      Хотя я тоже "ушел на Rust", но за развитием плюсов следить интересно.


  1. eao197
    22.03.2017 12:29

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


    1. antoshkka
      22.03.2017 12:41

      Это похоже на развитие контрактов. В данный момент этим занимаются все самые именитые С++ники и несколько очень умных человек, повёрнутых на доказательстве корректности программы на этапе компиляции. Есть несколько предложений, например вот тут предлагается нечто близкое к тому что в вашей статье про проверку исключений: possibly_throw_exception();

      Все эти десятки бумаг по контрактам ещё будут устаканиваться долгое время, [[implies(std::nothrow)]] появится не скоро. Сокро появятся только нечто наподобие:

      void push(int x, queue & q)
        [[expects: !q.full()]]
        [[ensures: !q.empty()]]
      {
        //...
        [[assert: q.is_valid()]];
        //...
      }
      


      1. eao197
        22.03.2017 12:47

        Контракты я использовал в Eiffel-е и, частично, в D. Во-первых, это не совсем про то. Контрактами, например, нельзя показать, что функция чистая. Или что она нерекурсивная. В том же D ввели отдельный атрибут pure, который к контрактам не относится. Во-вторых, что было для меня неожиданностью: Eiffel располагает к использованию контрактов, там это происходит само собой, естественным образом. А в D контракты хоть и были, но нужно было заставлять себя придерживаться дисциплины и описывать их.

        Ну и дело вообще-то не в том, чтобы [[implies(std::nothrow)]] появился. А чтобы движение началось :)


        1. 4144
          24.03.2017 17:22

          В gcc есть атрибуты pure, const, и много других. Хотя не уверен, что это то, что вы имели в виду.

          https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes


          1. eao197
            24.03.2017 17:27

            Есть, что наводит на мысль о том, что [[implies(std::pure)]] вполне себе реализуемо. Осталось чтобы:

            a) можно было выставлять требования для блоков кода (например, [[expects(std::pure)]]) с соответствующей диагностикой от компилятора в случае нарушения;
            b) включения этого в стандарт, чтобы это было не только в одном конкретно взятом компиляторе.


  1. TargetSan
    22.03.2017 12:45
    +2

    С модулями, концептами, рейнджами 3 и другими вкусностями всё ясно — их не будет минимум до С++20, а то и дольше. Хотелось бы узнать что-нибудь по другим фундаментальным вопросам


    1. Опакечивание. Какой-то более-менее стандартный формат описания пакета. Для начала пусть без центрального репозитория — хотя бы как в Go возможность просто стянуть репозиторий, который будет собран по своим правилам и подключен к сборке моего проекта. Без попыток вручную скрестить CMake, MSBuild, GNU Make, Autotools, BJam etc.
    2. Chosen nightly compiler. GCC может концепты, MSVC может модули, CLang может что-то ещё нужное (не помню). Попробовать это всё в связке нельзя по понятным причинам.
    3. Если такая большая проблема добавить ranges v3, есть ли шанс в обозримом будущем получить хотя бы набор iterator adaptors? Втащить Boost не всегда есть возможность.

    Я понимаю что в (1) и (2) требую слишком многого. Хотя нет — С++ единственный из мейнстрима, где нет конкретно (1) и катастрофический разброд касательно (2).


    1. antoshkka
      22.03.2017 12:54

      * Для (1) нужен работающий прототип, который всех устраивает. Такого нет и в ближайшем будущем не появится
      * С (2) вы всегда можете помочь — допишите нехватающий функционал в GCC/Clang ;-)
      * Пункт (3) ожидайте в скором времени во всех компиляторах поддерживающих концепты — ranges выпускаются в этом году в виде отдельного TS, который можно попробовать ещё до С++20.


      1. TargetSan
        22.03.2017 13:51

        (1) Я тихонько надеялся, что хотя бы о необходимости прототипа начинают задумываться. Впорчем, это отдельная тема для разговора.
        (2) Вопрос в том, что даже фулл-тайм я не смогу написать прототипы для всего, что может войти в стандарт, для одного компилятора.
        (3) Ключевое словосочетание "поддерживающих концепты". Последний раз, когда я интересовался вопросом, такое было только в отдельной экспериментальной ветке GCC. Нв других "столпах индустрии", насколько я знаю, состояние на нуле.


        1. antoshkka
          22.03.2017 15:18

          А для (2) фулл тайм и не требуется, вы недооцениваете свои силы:

          * Один человек не напрягаясь в свободное время может разгрести тьму ошибок, до которых у разработчика просто не доходят руки (например ищите Mikhail Maksimov в changelog Boost. 1.64)

          * Некоторые в свободное время просто берут, и добавляют недостающий им функционал. Вот например вам changelog GCC, в котором есть фраза «Thanks to Daniel Krugler, Tim Shen, Edward Smith-Rowland, and Ville Voutilainen for work on the C++17 support.». Что-то мне подсказывает, что эти ребята на GCC не работают.

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


    1. encyclopedist
      22.03.2017 17:14

      1. Так range-v3 вы можете использовать уже сейчас. Во всех нормальных компиляторах. Концепты там эмулируются старым добрыми добрыми шаблонами и макросами. Несколько дней назад авторы синхронизировали range-v3 с ranges TS.


      1. TargetSan
        22.03.2017 17:21

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


  1. DrSmile
    22.03.2017 13:48
    +1

    Напишу про синтаксический сахар, которого мне иногда не хватает.

    • Многократный break для выхода из вложенных циклов/switch:
      for(int i = 0; i < 100; i++)
        for(int j = 0; j < 100; j++)
          if(some_check(i, j))break break;
      
    • Последним в цепочке break может стоять continue — в этом случае будет продолжен соответствующий цикл.
    • continue для switch:
      switch(num)
      {
      case 1:   do_smth(1);   continue 3;  // переход к выполнению case 3
      case 2:   do_smth(2);   continue 3;  // аналогично
      case 3:   do_smth(3);   break;
      }
      


    1. Gorthauer87
      22.03.2017 15:12
      +2

      Лучше break на метку, впрочем, для этого есть goto, внезапно.


    1. OlegZH
      22.03.2017 15:40

      А как Вам такой код:

      A.for(int i = 0; i < 100; i++)
        B.for(int j = 0; j < 100; j++)
          if(some_check(i, j)) break (A);
      

      — для выхода из двойного цикла, и
      A.for(int i = 0; i < 100; i++)
        B.for(int j = 0; j < 100; j++)
          if(some_check(i, j)) break (B);
      

      — для выхода только из вложенного цикла?


    1. PsyHaSTe
      24.03.2017 19:34

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


  1. TargetSan
    22.03.2017 13:54
    +1

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


    Мне, к примеру, пришёл в голову такой вариант:


    a |> f(b, c)
    // превращается в 
    f(a, b, c)

    т.е. через отдельный оператор. Хотя их, наверное, и так хватает.


    1. Antervis
      22.03.2017 18:23

      1. TargetSan
        22.03.2017 18:32

        Всё бы хорошо, но 2014-10-04...


  1. OlegZH
    22.03.2017 14:41
    +1

    Всё сказанное выше убеждает меня в том, что язык C++ надо было уже давно «зафиксировать» в виде некоторого разумного стандарта и добиться строгой реализации этого стандарта. Если для разумности нужно будет пожертвовать чем-то, что кажется полезным, то лучше этим пожертвовать в пользу концептуальной чистоты языка. А все накопившиеся проблемы следует решать, создавая новый язык программирования.

    И тут возникнет важный вопрос: что должно стать органической частью нового языка программирования (на уровне ключевых слов и синтаксических конструкций), а что должно быть реализовано в виде поставляемых библиотек. Беда большинства языков программирования, как раз, в том и заключается, что происходит смешение, когда на одном и том же уровне организации оказывается и код приложения, и код реализации функций и компонентов, используемых в приложении.

    Например, на низком уровне находятся такие понятия как типы хранимых данных (символы, числа, строки, массивы, структуры...), на более высоком — домены (описывающие поля хранимых в базах данных объектов, которые, с одной стороны, используют для физического хранения и, возможно, для визуального представления какой-либо тип данных, а, с другой стороны, связаны с некоторой сущностью, принадлежащей концептуальной схеме базы данных), и на самом высоком уровне — уже сами сущности. Было бы крайне любопытно взглянуть на язык программирования, где реализована многоуровневая архитектура управления данными приложения…

    Я не говорю ещё о визуальных компонентах и операционной системе.

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

    Numbers TS

    Было бы очень хорошо! Всегда пытаешься «сварганить» нечто похожее доморощенными средствами. Но! Всё это потребует существенной «ломки» синтаксиса. Я бы мечтал о том, чтобы была возможность перегружать ",", "(", ")", ":" и многое другое, что позволило бы описывать прямо в коде конструкции произвольной сложности. Или всё это уже реализовано?

    И можно ли в C++ делать что-то по типу оператора with? Например, так:
    object{
    .Open();
    .Load();
    .Close();
    }
    

    Что я ещё пропустил (из предыдущих серий)?

    P.S. А ещё свойства (properties)! Есть ли какие-либо планы относительно свойств?


    1. antoshkka
      22.03.2017 14:43
      +3

      Лично мои планы относительно свойств очень масштабные: не допустить включения этой фигни в стандарт.


      1. iassasin
        22.03.2017 14:52

        А можете пояснить, почему вы не хотите их видеть в стандарте?


      1. OlegZH
        22.03.2017 15:04

        Я пропустил очень много предыдущих серий и не знаю, что там, вообще, происходило со свойствами (если происходило).

        Я имею в виду конструкцию, которая восходит ещё к Delpi:

        __property AnsiString Name = { read=FName, write=SetName };
        

        С этим элементом языка что-то не так?


        1. antoshkka
          22.03.2017 15:24
          +1

          Например очень многим они не нравятся: https://stdcpp.ru/proposals/07a6ff30-4f0e-4683-bbaf-4a635eadfb34

          А еще они не сокращают написание кода, делают его чтение сложнее, являются синтаксическим сахаром (к которому у меня необоснованная ненависть после Perl)… А ещё некоторые разработчики языков, где уже есть свойства, называют их «одной из ошибок при дизайне языка» и жалеют что в своё время их добавили (можете поискать по интернету ссылки).


          1. OlegZH
            22.03.2017 15:45
            +2

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


            1. antoshkka
              22.03.2017 15:52

              Вначале опишите свою идею на английском вот сюда и послушайте что люди говорят.


              1. OlegZH
                22.03.2017 16:03

                Thanks. Very interesting. :-)


          1. PsyHaSTe
            24.03.2017 19:38
            +1

            Поискал, не нашел. В чем же беда свойств? В шарпе они хорошо себя зарекомендовали, их постоянно разивают, не бросают как Legacy. У них же куча плюсов: их можно объявляь в интерфейсе (сверхполезнаа фича), на них можно вешать валидацию… Мне скорее кажется, что концепция полей не нужна — пусть компилятор сам имплементирует свойства самого низкого уровня как поля. А то получается путаница как в уже упомянутом шарпе: есть поля, есть свойства, в рефлексии они выглядят по-разному и т.п. Была бы одна сущность (с возможностями свойств) — было бы легче.


      1. mezastel
        23.03.2017 02:09
        -3

        Свойства прекрасно показали себя в C# и поэтому просто должны быть добавлены в С++ по тем же причинам. Я уже правда использую свойства, т.к. меня не волнует standards compliance, __declspec(property) наше всё. Я даже сподвиг ребят из ReSharper C++ добавить генераторы для этого. Но хочется чтобы это все-таки вошло как часть языка.


    1. Sirikid
      22.03.2017 17:20

      Всё сказанное выше убеждает меня в том, что язык C++ надо было уже давно «зафиксировать» в виде некоторого разумного стандарта и добиться строгой реализации этого стандарта. Если для разумности нужно будет пожертвовать чем-то, что кажется полезным, то лучше этим пожертвовать в пользу концептуальной чистоты языка.

      В этом же сила C/C++: минимум оверхеда, пусть и шаг влево, шаг вправо — UB.


      [следующие четыре абзаца]

      Все языки балансирует между DSL и метаязыком — языком для создания DSL.


      Numbers TS

      Было бы очень хорошо! Всегда пытаешься «сварганить» нечто похожее доморощенными средствами. Но! Всё это потребует существенной «ломки» синтаксиса.


      Нет, ведь в C++ можно перегружать нужные операторы.


      Я бы мечтал о том, чтобы была возможность перегружать ",", "(", ")", ":" и многое другое, что позволило бы описывать прямо в коде конструкции произвольной сложности. Или всё это уже реализовано?

      F# (и, вроде, OCaml и SML) — пользовательские операторы, приоритеты и ассоциатиность фиксированы, Haskell, Idris — пользовательские операторы с пользовательскими приорететами и ассоциативностью, Agda — mixfix.


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


      1. develop7
        23.03.2017 21:01

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

        https://github.com/commercialhaskell/describe немного помогает


    1. Antervis
      22.03.2017 18:30

      Я бы мечтал о том, чтобы была возможность перегружать ",", "(", ")", ":"

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


  1. Idot
    22.03.2017 17:31

    Почему в опросе нет абсолютно никакого пункта про поддержку строковых переменных в Юникоде?
    Вот уже двадцать лет, как хочется материться из-за того, что стандарты C++ полностью игнорируют UNICODE!


    1. antoshkka
      22.03.2017 18:25

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


      1. Antervis
        22.03.2017 19:01

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


        1. encyclopedist
          22.03.2017 21:32
          +2

          Есть 2 большие проблемы: 1. Это далеко не однозначная вещь, как это должно работать. Юникод гораздо сложнее чем может показаться. См. utf8everywhere.org там хорошо расписаны разные проблемы.


          1. Для поддержки юникода нужны довольно объемные таблицы (до мегабайт размером), которые не получится тащить на микроконтроллеры например. Поэтому поддержку юникода придётся делать опциональной.


          1. grossws
            23.03.2017 02:15

            довольно объемные таблицы (до мегабайт размером)

            libicudata.so.58.2 весит 25+ MiB, остальные поменьше, мегабайты, а не десятки. Весь набор libicu без утилит весит 30+ MiB


      1. Scf
        23.03.2017 08:23

        Есть же QString из QT. Или хотя бы с Java слизать API по работе с юникодом. Оба варианта существуют больше 10 лет.


        1. knstqq
          23.03.2017 10:14
          +1

          >> QString stores a string of 16-bit QChars, where each QChar corresponds one Unicode 4.0 character. (Unicode characters with code values above 65535 are stored using surrogate pairs, i.e., two consecutive QChars.)

          Это qt 5.8 — так себе Unicode поддерживается QString'ом, не нужно ничего с таким качеством поддержки в стандарт совать.
          я не в комитете, но имхо не нужно такого в стандарте, против я.


          1. Antervis
            23.03.2017 10:37

            Юникод же так и работает. Если код символа слишком большой для одной позиции, то он кодируется двумя или более последовательными позициями. В Qt используется либо ICU, либо собственная реализация, в зависимости от флагов компиляции.


  1. Loginin
    23.03.2017 11:37

    SIMD очень хочется нормальный. И в алгоритмах (желательно с поддержкой функций как в OpenMP, но как минимум simd execution mdoel для алгоритмов), так и на уровне типов данных (желательно с поддержкой адаптирующейся ширины, чтобы не делать Vec<Int, 4> для SSE, Vec<Int, 8> для AVX2 и Vec<Int, 16> для AVX512).


    1. mezastel
      23.03.2017 16:37

      Мне кажется просто нужны нормальные операторы для операций над массивами, по аналогии с Intel SPMD: если я пишу a*b и a и b — это массивы, то операция должна векторизоваться. Ну а если матрицы, должна вызываться соответствующая рутина. Сейчас все это спрятано под ширмой MKL, но пользоваться этим намного более напряжно чем например в MATLAB. Вообщем проблема в том, что массивы/матрицы криво стандартизованы и неоптимально реализованы. А скалярные операции над SSE/AVX регистрами это более редкое явление.


      1. encyclopedist
        23.03.2017 17:14
        +1

        Посмотрите на Eigen например


        1. mezastel
          26.03.2017 10:52

          Уже использую :)