В настоящее время я экспериментирую с разработкой класса InputHandler, который будет отвечать за хранение функций обратного вызова, зарегистрированных в его экземпляре из различных объектов, и вызов этих функций при возникновении необходимых действий и событий.Для этого у меня есть такая структура: (отредактировал и написал всю структуру)
struct EventContainer {
public:
EventContainer();
EventContainer(EventType t, SDL_Scancode k, std::function<void()>&& cb, int pid) : Type(t), m_Key(k), Callback(cb), m_ID(pid) {}
EventContainer(const EventHolder& c) : Type(c.Type), m_Key(c.m_Key), Callback(c.Callback), m_ID(c.m_ID) {}
int m_ID;
std::function<void()> Callback;
EventType Type;
SDL_Scancode m_Key;
private:
friend bool operator==(const EventContainer& lhs, const EventContainer& rhs)
{
return lhs.m_ID == rhs.m_ID;
}
};
std::vector<EventContainer> eventCallbacks; // Vector to store all event callbacks.
Пока все хорошо, тогда я создал метод для привязки определенного события.
void BindMethod(std::function<void()>&& callback, // other params for struct)
{
EventContainer cb;
cb.Callback = callback;
// other params
eventCallbacks.push_back(std::move(cb));
}
В основном цикле я проверяю вектор eventCallbacks в соответствии с другими его параметрами, и если мне нужны истинные условия, я запускаю соответствующий Callback.Пока у меня нет проблем с этим.Теперь прибывает моя пара проблем и вопросов.
Существует 3 способа, насколько я могу проверить, что я могу вызвать этот BindMethod, чтобы зарегистрировать обратный вызов.Мне интересно, чем они отличаются?Особенно в отношении памяти, и я также, конечно, хотел бы узнать, почему.
Первый метод:
input->BindMethod(&TestMethod1); // I have a simple method, returning void, with no params called TestMethod1
Работает замечательно, однако я не могу передать никаких параметров.Конечно, всегда есть возможность создания шаблонов и поддержки нескольких аргументов, но я не хочу чрезмерно усложнять вещи с помощью модульности или «универсальности».Мне просто нужно получить то, что мне нужно.
Итак, есть второй вариант ...
auto f = std::bind(TestMethod2, 5, 2); // 5,2 are my params for TestMethod2.
input->BindMethod(f);
Этот тоже работает замечательно, однако я не создал много тестовых случаев для этого.только базовые, так что не могу точно сказать.Плюс из того, что я исследовал, сообщество не любит std :: bind так сильно.
И там идет волшебная лямбда, третий путь
auto f2 = [testInteger] { TestMethod3(testInteger); };
input->BindMethod(f2);
Лямбда-способ работы вещей работаетдовольно круто, однако, я подозреваю, что в этом случае у меня возникает вопрос: что если экземпляр объекта, который содержит функцию-член внутри лямбда-тела, умирает до того, как событие когда-либо сработает, и будет вызван обратный вызов, и хуже, что еслиобратный вызов будет вызван после того, как объект умер?Таким образом, мы должны реализовать какой-то механизм, который выведет соответствующую структуру обратного вызова из векторного массива, верно?Однако, насколько я видел, удалить структуру из векторного массива довольно проблематично.Сначала я дал несколько идентификаторов для объектов struct, затем я попытался сделать это внутри определенного метода привязки:
void Unbind(int pid)
{
EventCallbacks.erase(std::remove_if(EventCallbacks.begin(), EventCallbacks.end(), [&](EventContainer const & holder) {return holder.id == h.GetID(); }), EventCallbacks.end());
}
Однако моя программа потерпела крах.Я проверил pid, который передается правильно, и я проверил, что holder.id является правильным и соответствует pid, но каким-то образом программа вылетает, вероятно, что-то связанное с итератором, и не может найти причину.
Итак, подведем итоги:
- Принципиальные различия между этими тремя методами для вызова метода BindMethod.И если есть еще варианты, которые можно использовать, или какие-либо идеи, мысли?
- Является ли это хорошим способом организации обработки обратного вызова события?У меня есть структура с методом обратного вызова и всеми остальными данными, которые мне нужно проанализировать, и вектор этих структур для вызова методов при необходимости.
- Мне определенно нужен надежный и конкретный способ поиска иУдаление элемента вектора без сбоя, также необходимо понять, почему происходит сбой.Изменить: немного больше исследований, вероятно, из-за смещения вектора вызывает после удаления.Однако, поскольку я обнаружил, что списки не вызывают смещения, существует более линейный подход к вставке и удалению.Итак, было бы лучше переключиться на списки вместо векторов?Поскольку мне не нужно иметь произвольный доступ к какому-либо элементу внутри моей коллекции, все, что я буду делать, это итерировать его с постоянной частотой кадров.
- Как насчет опасностей в средствах выделения памяти при использованииstd :: function?Безопасно ли основывать мою архитектуру или я должен пойти по более лучшему пути?
- Есть ли какие-либо шаги, которые я должен предпринять при удалении объектов структуры из вектора с помощью средствосвободить память?Есть ли что-то, что я должен быть осторожным?
- Я действительно чувствую себя не очень комфортно, когда использую std :: vectors или вообще что-то в std.Существуют ли другие дешевые, функциональные подходы?
Заранее благодарим и приносим извинения за любые неправильные представления и термины, которые я мог бы использовать, или за отсутствие предоставления правильной информации.