1. C++ / Говнокод #27309

    +3

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    template<typename T>
    struct [[nodiscard]] InplacePointerGuard {
        InplacePointerGuard(T *& ptr_) : ptr(ptr_) {}
        ~InplacePointerGuard()
        {
            if (ptr != nullptr) {
                ptr->~T();
            }
        }
    
        T *& ptr;
    };
    
    template<typename EventType, typename... Args>
    bool publishEmplace(Args &&... args) const
    {
        static_assert((std::is_base_of_v<Event, EventType> && std::is_convertible_v<const EventType *, const Event *>),
                      "EventType must be a public subtype of Event");
        auto typeIdx = Event::getStaticIndex<EventType>();
    
        std::aligned_storage_t<sizeof(EventType), alignof(EventType)> eventStorage;
        EventType *eventConstructed = nullptr;
        auto guard = InplacePointerGuard(eventConstructed);
    
        publishEmplaceImpl<EventType>(typeIdx, eventStorage, eventConstructed, std::forward<Args>(args)...);
    
        return eventConstructed != nullptr;
    }
    
    template<typename EventType, typename... Args>
    static EventType *constructEvent(std::aligned_storage_t<sizeof(EventType), alignof(EventType)> & eventStorage,
                                     Args &&... args)
    {
        return std::launder(new(&eventStorage) EventType(std::forward<Args>(args)...));
    }
    
    template<typename EventType, typename... Args>
    void publishEmplaceImpl(const std::type_index & typeIdx,
                            std::aligned_storage_t<sizeof(EventType), alignof(EventType)> & eventStorage,
                            EventType *& eventConstructed,
                            Args &&... args) const
    {
        if (auto it = callbacks.find(typeIdx); it != callbacks.end()) {
            for (const auto & [subId, callback] : it->second) {
                if (!eventConstructed) {
                    eventConstructed = constructEvent<EventType>(eventStorage, std::forward<Args>(args)...);
                }
                callback(*eventConstructed);
            }
        }
    
        auto range = EventsRelation::RelationManager::getParentsRange(typeIdx);
        for (auto it = range.first; it != range.second; ++it) {
            if (!eventConstructed) {
                publishEmplaceImpl<EventType>(it->second, eventStorage, eventConstructed, std::forward<Args>(args)...);
            } else {
                publishImpl(it->second, *eventConstructed);
            }
        }
    }

    Запостил: PolinaAksenova, 22 Марта 2021

    Комментарии (66) RSS

    • > Явно используется С++11, судя по auto.

      > Переизобретённый unique_ptr с функцией выстрела в ногу.
      Ответить
      • > unique_ptr

        Это больше на auto_ptr похоже... Хотя не, вообще какая-то странная дичь.
        Ответить
        • Скоро вообще не надо будет думать про типы, просто пишешь auto_ptr(auto*&auto) и конпелятор сам все делает.
          Ответить
        • unique_ptr с делитером не освобождающем память. Ну и за которым нужно следить, чтобы случайно не скопировать.
          Ответить
          • А хотя погоди, туту же ссылка. Согласен. Неведомая Ёбаная дичь.
            Ответить
            • Места на стеке под временный объект не хватило что ли... Зачем ещё пихать временную фигню в глобалку и обрезать ей время жизни до обычной локалки. Реально дичь какая-то, ещё и однопоточная.

              Бля, aligned storage в локалке и хранится...
              Ответить
            • Короче я кажется понял что это, это эмуляция std::optional.
              Ответить
      • я вообще не понял, как это используется

        там же нулптр сразу
        EventType *eventConstructed = nullptr;
        auto guard = InplacePointerGuard(eventConstructed);
        Ответить
    • Пиздец, это какая-то квинтэссенция крестозла. Здесь и, блять, [[теги]] вот эти, и метушня, и троеточия, чего здесь только нет. Мне страшно такое читать.
      Ответить
      • Да тут даже std::launder есть...
        Ответить
        • Забавно, что никто не спросил "а что это?" Видимо все в курсе.
          Ответить
          • И родня вся, и сама Батисса стали стучаться к нам, и рты разинув разглядывать, будто у нас на кухне сидела сама Сонми. Вопросы о провидцах и их корабле потоком бурным полились:
            - А как корабль по волнам скользит так бесшумно?
            - Термоядерные двигатели.
            Но что есть суть "термоядерные двигатели" никто не спросил, ибо не хотел предстать глупцом.
            Ответить
          • я сходил в цппреференс

            >Obtains a pointer to the object located at the address represented by p.
            Сепульничает, короче:)

            Я так понял, я не могу скастить указатель на кусочек говна в памяти в оьъект, бо лейаут. Для этого и нужен этот стирательный машинк
            Ответить
            • На самом деле в данном случае std::launder избыточен, поскольку память не переиспользуется. Более подробно: https://habr.com/ru/post/540954/.
              Ответить
              • Типа вот у нас есть const nemyx, он висит в куче, а потом мы его удалили НО адрес всё ещё зашкварен константностью немуха, поэтому надо за ним помыть с помощью std::launder, а то компилёр может ниче не писать в ту память?
                Ответить
              • спасибо, понял
                Ответить
            • s/лейаут/алайнмент/
              Ответить
            • Не совсем. Емнип, оно возвращает поинтер, очищенный от инвариантов, которые конпелятор навыводил для исходного поинтера. Т.е. если конпелятор знал, что p->x == 42 и мог заюзать это при оптимизациях, то про std::launder(p)->x он ничего не знает.
              Ответить
              • Понятно, ну это еще одна из причин, по коим нельзя кастить напрямую в указатель на объект.

                Грубо говоря, если работал с объектом только через указатель foo, и никогда не трогал его поле x, то компилятор может там любой хуйни наворотить.

                А потом я прихожу, и говорю: "тут была где-то память? так вот она объект, хочу с ним работать"

                Вот тут и нужен лондер
                Ответить
                • Не, если у тебя была память (void* ?), то launder по идее не нужен. Конпелятор и так нихрена интересного про неё не знает.

                  А вот если у тебя был объект и ты поверх него через placement new хуйнул другой объект того же типа -- вот тут нужен. Если указатель не обмыть, то конпелятор может какие-то старые факты про старый объект вспомнить и применить к новому.
                  Ответить
                  • ах, пиздец)

                    то есть проблема в том, что я сначала в памяти имел Instance1 класса foo, а потом хуйнул туда Instace2, а компилятор думает, что указатель-то всё еще на Instance1, и он про него вывел какие-то знания (например, что x всегда равен 42) и стиратель просит компилятора всё это забыть?
                    Ответить
                  • типа так
                    class Foo
                    {
                    public:
                    	int foo = 1;
                    };
                    
                    int main()
                    {
                    	auto* foo = new Foo;
                    	foo->foo = 2;
                    	std::cout << foo->foo;
                    	new(foo) Foo;
                    	//отличный повод помыть foo
                    	std::cout << foo->foo;
                    }
                    Ответить
                    • Да даже здесь вроде всё норм т.к. const и & полей в Foo нету...

                      std::launder -- это такой тонкий corner case, что на практике ты его хуй встретишь если не будешь свою стандартную либу метушить.
                      Ответить
                      • "норм" это мне просто повезет, или реально не нужно мыть? UB не будет?

                        Про const Лолечка заметил https://govnokod.xyz/_27309/#comment-602789
                        Ответить
                        • Без констов вроде норм. Там мутно в стандарте, но вроде если нет конст и ссылок, то новый объект вступит в силу сразу после new. Т.е. конпелятор обращения к неконстантной фигне не так жестко оптимизирует.
                          Ответить
                          • >Там мутно в стандарте,
                            понятно, лучше лондарить

                            а еще лучше не переиспользовать память, а освобождать её, и брать снова
                            Ответить
        • ну это вроде производитель косметики такой
          Ответить
      • Угадай автора по коду
        Ответить
        • Я на борманда думаю, на j123123 не очень, потому что он по сишке... Ещё был тот самый, у которого на аватарке ким-пять-с-плюсом, мог он написать. Ещё, вроде бы, Снаут умеет в ТАКИЕ кресты... Кого-нибудь мог забыть.

          А ты на кого думаешь?
          Ответить
          • Автор PolinaAksenova же
            Ответить
            • https://github.com/htmlacademy-htmlcss/1563617-sedona-30

              А ты знаешь «С++» экспертного уровня?
              Ответить
              • >html academy

                Ну вот вы тут шутили про доктора в вопросах колбасы, а у HTML целые академики есть.

                Моя Альма-Матер -- Высшая Школа CSS.
                Ответить
                • При этом они питушут ТАКОЙ код на плюсах, боюсь представить чем занимаются крестоакадемики.
                  Ответить
                  • На крестах пишет всякая чернь. Крестоакадемики пишут крестостандарт.
                    Ответить
          • Я только в `modern' С++ умею, а это уже какое-то post-modern.
            Ответить
          • > Я на борманда думаю

            Не, я обычно намного проще пишу. Изъёбываться я начинаю только если пирфоманс/размер прям сильно поджимает.
            Ответить
            • Изьёбывацца у нас гост любит)
              Ответить
              • Действительно, похоже на него. Ушел, а вернулся в шляпе, и с синими волосами
                Ответить
                • gost всем доброго утра желал.
                  Ответить
                • > вернулся в шляпе, и с синими волосами

                  Аниме пожирает уютный говнокодик.
                  Ответить
            • > Изъёбываться я начинаю только если пирфоманс/размер прям сильно поджимает.

              Так ведь если пирфоманс/размер прижимает, надо не нечитаемую срань на крестах писать, а брать сишку с ассемблерными вставками. Или вообще чистый асм.
              Ответить
              • И то правда.

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

              По ней где-то десятка два событий в секунду ходит.
              Ответить
    • https://twitter.com/Badou_N/status/1359432343157637124
      Ответить

    Добавить комментарий