Кресты / Говнокод #27309 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  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 PolinaAksenova, (Updated )

Комментарии (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);
      Ответить
  • Пиздец, это какая-то квинтэссенция крестозла. Здесь и, блять, [[теги]] вот эти, и метушня, и троеточия, чего здесь только нет. Мне страшно такое читать.
    Ответить
      • Забавно, что никто не спросил "а что это?" Видимо все в курсе.
        Ответить
        • И родня вся, и сама Батисса стали стучаться к нам, и рты разинув разглядывать, будто у нас на кухне сидела сама Сонми. Вопросы о провидцах и их корабле потоком бурным полились:
          - А как корабль по волнам скользит так бесшумно?
          - Термоядерные двигатели.
          Но что есть суть "термоядерные двигатели" никто не спросил, ибо не хотел предстать глупцом.
          Ответить
        • я сходил в цппреференс

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

          Я так понял, я не могу скастить указатель на кусочек говна в памяти в оьъект, бо лейаут. Для этого и нужен этот стирательный машинк
          Ответить
            • Типа вот у нас есть const nemyx, он висит в куче, а потом мы его удалили НО адрес всё ещё зашкварен константностью немуха, поэтому надо за ним помыть с помощью std::launder, а то компилёр может ниче не писать в ту память?
              Ответить
          • Не совсем. Емнип, оно возвращает поинтер, очищенный от инвариантов, которые конпелятор навыводил для исходного поинтера. Т.е. если конпелятор знал, что 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, что на практике ты его хуй встретишь если не будешь свою стандартную либу метушить.
                    Ответить
                      • Без констов вроде норм. Там мутно в стандарте, но вроде если нет конст и ссылок, то новый объект вступит в силу сразу после new. Т.е. конпелятор обращения к неконстантной фигне не так жестко оптимизирует.
                        Ответить
                        • >Там мутно в стандарте,
                          понятно, лучше лондарить

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

        А ты на кого думаешь?
        Ответить
        • Я только в `modern' С++ умею, а это уже какое-то post-modern.
          Ответить
        • > Я на борманда думаю

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

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

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

            По ней где-то десятка два событий в секунду ходит.
            Ответить

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

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8