Обновить
4
Антон Семенов@allcreater

Программист С++

2
Подписчики
Отправить сообщение

даже не знаю, что делать дальше

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

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

Недостаток авторского решения в отсутствии синтаксической подсветки лямбд (стринга и стринга), но в случае изменения интерпретатора придётся и вовсе патчить плагин IDE, чтобы он тоже понимал такие выкрутасы… Хотя по производительности и правда гораздо дешевле
На плюсах не обязательно такой ужас городить.
Отбросим аргументы шаблона, которые и так дефолтные, ну и заменим unordered_set на set для читаемости:

enum class Fruit { Apple, Orange, Kiwi };
std::set<Fruit> X;
Извините, конечно, но разобраться по контексту, что делает та или иная конструкция, и написать её без знания языка — вещи совершенно разные.

Если угадать, что делает |x|*n по контексту(как и большинство других конструкций в других языках программирования) может большинство более-менее опытных разработчиков, то для того, чтобы додуматься так написать без примера, нужно обладать ну очень богатой фантазией.
Идея опроса интересная и реализация тоже неплоха, но обязательность выбора «худшего работодателя» напрягает. Из всего списка лично я знаю пару десятков компаний, работал в двух из них, были свои плюсы и минусы(«как и у всех остальных источников питания»©​), но преимущества, по моему мнению, таки с лихвой перевешивали недостатки.

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

И вот тут непонятно, ожидается ли, что должен я указать недостоверные подозрения о компании, которую считаю плохой, или отвечать более-менее объективно, но о работодателе, к которому особых претензий не имею?

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

Хотел только добавить, что Вы зря прибедняете C# насчёт корутин :)

Там они именно что есть, да ещё и в двух разных вариантах, обуславливаемых разными синтаксическими конструкциями - yield return / yield break и await.

Более того, именно из C# корутины приехали в C++, это было предложение Майкрософтов, вдохновлённое наработками из развиваемого ими языка.

Только корутины в C++, будучи развитием уже отработанного подхода, чуть более универсальны: у нас тоже есть три ключевых слова co_yield, co_return и co_await, (на "кококо" все ругаются, но Комитет побоялся использовать для ключевых слов распространённые английские слова, чтобы не ломать обратную совместимость) но по сути это всё - частные случаи оператора co_await.

Так ведь ради краткости и эффективности кода ведь всё и задумывается, причём в эту сторону движутся и C#, и C++, и все остальные языки программирования!

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

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


Однако это - библиотечный тип, его реализовали один раз опытные люди, и теперь простым смертным достаточно его только использовать:

#include <cppcoro/generator.hpp>

using namespace cppcoro;
using namespace std;

generator<uint64_t> fibonacci()
{
    uint64_t a = 0, b = 1;
  
    while (true)
    {
        co_yield b;
    
        auto tmp = a;
        a = b;
        b += tmp;
    }
}

void usage()
{
    for (auto i : fibonacci())
    {
        if (i > 1'000'000) break;
        cout << i << endl;
    }
}

В C# это выглядело бы примерно так:

using System;
using System.Collections.Generic;

IEnumerable<UInt64> Fibonacci()
{
    UInt64 a = 0, b = 1;
  
    while (true)
    {
        yield return b;
    
        var tmp = a;
        a = b;
        b += tmp;
    }
}

void Usage()
{
   foreach (var i in Fibonacci())
   {
       if ( i > 1000000 ) break;
       Console.WriteLine( i );
   }
}

Велика ли разница? :)

Как видите, страшные языковые и библиотечные возможности понадобились для реализации типа самой корутины (IEnumerable в C# - почти полный аналог generator, а Task весьма похожа на нашу future (правда, в полнофункциональном виде пока существующую не в стандарте, а только в реализации Microsoft) ).

В C# опытные программисты тоже реализуют поддержку yield return / await у произвольных типов, и это такая же нетривиальная задача, как в C++.

К сожалению, последний опубликованный language reference по C#, который мне удалось найти — только 5ый, так что сравнить его длину с 9ым не получается по чисто техническим причинам. Впрочем, референс по C# 5 занимает приблизительно 500 страниц, возьмём за отправную точку.

Вроде немного по сравнению с C++ (в документе n4830, например, их уже аж 1802 штуки). Однако в стандарте C++ описан не только язык, но и стандартная же библиотека, в то время как BCL в референсе по языку отсутствует, что довольно логично, но мешает сравнить.

И всё-таки, давайте предметно, пожалуйста. Что именно из новых фич Вы не можете прочитать без боли? Чтобы далеко не бегать, предлагаю обсудить какой-нибудь кусок кода из обсуждаемого цикла статей.

Если хотите уровнять наши страдания, можете тоже предложить мне посмотреть на какой-нибудь кусок кода на шарпах, я попробую рассказать, что кажется неправильным мне =)
Ухх, спасибо огромное за примеры, лично я даже не подозревал о такой подставе с <=> =)

Без нормальных оптимизаций использовать эту штуку вместо операторов сравнения действительно страшновато.

С другой стороны, это детали реализации, рано или поздно вендоры доведут её до ума, и с каждой версией компилятора программы могут становиться быстрее и быстрее, а писать их вполне можно начинать уже сейчас.
> в котором C++20 поддерживается ощутимо лучше.
Судя по табличке cppreference.com, там уже почти все фичи реализовали, как библиотечные, так и языковые (хотя недоделки и есть, куда без них).

Честно говоря, тоже ещё не привык думать в стиле c++20, однако при освоении 17ых те же чувства были, правда? Значит, пара месяцев практики — и новой версии начнёт не хватать =)

С поддержкой новых компиляторов, к сожалению, «жиза»… У нас, например, только-только на C++17 переходят, и это не так уж плохо, есть гораздо более консервативные проекты.
А на мой вот взгляд всё с точностью до наоборот, C# сильно раздулся со времен этак пятой редакции, при этом особой лаконичностью там не пахнет.

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

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

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

И это если сравнивать код на C++20 и 17. Разница же между C++20 и 98 видна невооруженным взглядом.

Как и с любыми другими наборами инструментов, стандартную библиотеку нужно уметь использовать. Впрочем, за исключением буквально пары языковых фич, не работающих без поддержки со стороны стандартной библиотеке (std::inializer_list, std::type_info, например), использовать std вовсе не обязательно. Можете написать свою, или использовать сторонние.
Если вдруг Вам всё ещё не хватило видео, есть потрясный цельный курс лекций по современному языку. Возможно, уже неактуально, но упомянуть его, как мне кажется, стоило.

Если хочется попрактиковаться — есть курс от Yandex и МФТИ. Теория доступна любому зарегистрированному пользователю, практика по платной подписке.

Уверен, что есть и другие прекрасные материалы, но эти опробованы на своей шкуре :)
Вроде у Лукьяненко был только «Мой папа — антибиотик», про сына космодесантника.
А вот очень похожая на сабж история была в рассказе «Мы не рабы» — с тем отличием, что Земля судила колонии, но грозило это в большинстве случаев не экстерминатусом, а серьезными ограничениями.
Мне кажется, проблема в том, что это заставляет много думать ещё и ни в чём не повинных людей, которые будут потом читать и дорабатывать код :) Объявление на месте в современных языках позволяет сузить область видимости переменных и упрощает восприятие программы.
Спасибо за статью!

Извините, а рекомендация анализатора N1 точно поможет хоть что-то улучшить? По идее, для вызова конструкторов копирования/перемещения emplace_back и push_back ведут себя практически эквивалентно.

Функция substr вернёт rvalue, push_back практически у всех контейнеров имеет перегрузку, принимающую правостороннюю ссылку, а значит, в контейнер вставится объект всего лишь с двумя вызовами конструктора (внутри substr, и move-конструктор при запихивании объекта в список).

Ну а emplace_back примет аргумент по универсальной ссылке, которая так же преобразуется в rvalue reference, и явно вызовет конструктор копирования с этой ссылкой. То есть опять конструктор внутри substr и move-конструктор.

Попробовал проверить на вот таком вот коде, моё предположение вроде как подтверждается.

С другой стороны, если в коде из предложения N3 optionAreas — это std::vector<fheroes2::Rect>, то здесь emplace_back как раз-таки не помешает, поскольку укоротит код, и позволит действительно создать подобъекты внутри вектора, а не копировать их снаружи.

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

Спасибо за статью!
По C++ есть очень интересный цикл C++ Weekly, вдруг кто не видел.
Подавлящее большинство выпусков — 5-20 минутный ликбез по какой-то фиче языка, но есть и исключения.

Автор недавно ещё и книгу выпустил, «C++ Best Practices by Jason Turner»
Нууу, положим, местами гайдлайны мешают сильнее, чем технические ограничения :) С отладкой, подключением библиотек и подобными штуками проблем сейчас действительно нет и быть не должно, но де-факто плюсы получаются и правда «урезанные».

Например, UHT накладывает кучу ограничений на «публичные для движка» хэдеры — нельзя использовать шаблоны, алиасы, private и protected наследование. Узкий выбор контейнеров, и даже не все встроенные контейнеры можно выставить в публичный интерфейс.
Возможности «стандартной библиотеки UE» всё-таки далековаты от возможностей стандартной библиотеки C++. Маловато алгоритмов, некоторые реализованы неоптимально. Эксепшны не должны вылезать за границы пользовательского кода. Нет (во всяком случае, в версии 4.23 не было) прекрасных штук вроде std::string_view, std::variant(на самом деле есть TVariant, но почти не юзабельный), std::exchange. Плохая интеграция с STL, когда всё-таки хочется использовать его под капотом — скажем, нельзя просто так взять и подсунуть контейнер UE4 в алгоритм STL.

Некоторые внутренние механизмы самого движка балансируют на грани Undefined behavior.

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

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

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

Информация

В рейтинге
Не участвует
Откуда
Кипр
Дата рождения
Зарегистрирован
Активность

Специализация

Десктоп разработчик, Разработчик игр
Старший
C++
Библиотека стандартных шаблонов
C++ stl
ООП
C#
OpenGL
Vulkan API
Разработка игр