From 56c93d5b1ba152c1802d057e27591fee0b57feaf Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Fri, 5 Jun 2026 21:05:39 +0700 Subject: [PATCH] Fix Undefine behevior --- Delegate/Delegate.h | 592 +++++++++++++++++++++++--------------------- 1 file changed, 310 insertions(+), 282 deletions(-) diff --git a/Delegate/Delegate.h b/Delegate/Delegate.h index 1548fb8..0bf0ead 100644 --- a/Delegate/Delegate.h +++ b/Delegate/Delegate.h @@ -1,333 +1,361 @@ -#pragma once +#pragma once +#include #include +#include -template +/* + * Этоот класс по своей сути односвязный список, + * каждый элемент которого - подписавшийся объект. + * Реализация для случая когда Type_Parameter != void + */ + +template class Delegate { - struct DelegateDataBase + class ObjectWasDelete : public std::runtime_error { - virtual ~DelegateDataBase() = default; - DelegateDataBase* next = nullptr; - long long Hash = 0; - virtual void Call(TypeParameter) = 0; + public: + ObjectWasDelete() : std::runtime_error("Delegate (call): Object was delete") {} }; - - template - struct DelegateDataForClass : DelegateDataBase + + /* + * Базовая структура для записи подптсок + */ + struct BaseListData { - T* object = nullptr; + std::shared_ptr next; + virtual ~BaseListData() = default; + virtual void call(Type_Parameter data) = 0; + }; - typedef void(T::*Method)(TypeParameter); + template + struct ObjectListData : public BaseListData + { + using Method = void(Type_Object::*)(Type_Parameter); + std::weak_ptr object; Method method = nullptr; - - void Call(TypeParameter data) override + + ObjectListData() = default; + ObjectListData(std::weak_ptr object, Method method) : object(std::move(object)), method(method) {} + void call(Type_Parameter data) { - (object->*method)(data); - } - }; - - struct DelegateDataForFunction : DelegateDataBase - { - typedef void(*Func)(TypeParameter); - Func func = nullptr; - - void Call(TypeParameter data) override - { - func(data); + if (auto shared_object = object.lock()) + { + (shared_object.get()->*method)(data); + } + else + { + throw ObjectWasDelete(); + } } }; - DelegateDataBase* firstElement = nullptr; - - std::mutex mDelegateList; - - static constexpr unsigned int FNV1a(const char* str, unsigned int n, unsigned int hash = 2166136261U) { - return n == 0 ? hash : FNV1a(str + 1, n - 1, (hash ^ str[0]) * 19777619U); - } + struct FunctionListData : public BaseListData + { + void(*function)(Type_Parameter); + FunctionListData() = default; + FunctionListData(void(*func)(Type_Parameter)) : function(func) {} + void call(Type_Parameter data) + { + function(data); + } + }; + + std::shared_ptr list_head = nullptr; + std::mutex m_list; public: - template - void bind(T* object, void(T::*method)(TypeParameter)) + template + void bind(std::weak_ptr object, void (Type_Object::*method)(Type_Parameter)) { - char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))]; - const char* ptrToObjectRef = reinterpret_cast(&object); - for (long unsigned int i = 0; i < sizeof(T*); ++i) - str[i] = ptrToObjectRef[i]; - - const char* ptrToMethodRef = reinterpret_cast(&method); - for (long unsigned int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)(TypeParameter)); ++i) - str[i] = ptrToMethodRef[i - sizeof(T*)]; - - DelegateDataForClass* data = new DelegateDataForClass; - data->next = firstElement; - data->object = object; - data->method = method; - data->Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)(TypeParameter))); - - delete[] str; - - mDelegateList.lock(); - firstElement = data; - mDelegateList.unlock(); + if (!object.expired() && !method) + return; + + std::lock_guard lock(m_list); + std::shared_ptr old_head = list_head; + list_head = std::make_shared>(object, method); + list_head->next = old_head; } - - void bind(void(*func)(TypeParameter)) - { - char* str = new char[sizeof(void(*)(TypeParameter))]; - const char* ptrToFuncRef = reinterpret_cast(&func); - for (int i = 0; i < sizeof(void(*)(TypeParameter)); ++i) - str[i] = ptrToFuncRef[i]; - DelegateDataForFunction* data = new DelegateDataForFunction; - data->next = firstElement; - data->func = func; - data->Hash = FNV1a(str, sizeof(func)); - delete[] str; - - mDelegateList.lock(); - firstElement = data; - mDelegateList.unlock(); - } - - template - void unbind(T* object, void(T::*method)(TypeParameter)) + void bind(void(*function)(Type_Parameter)) { - if (firstElement == nullptr) - return; - - char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))]; - const char* ptrToObjectRef = reinterpret_cast(&object); - for (long unsigned int i = 0; i < 8; ++i) - str[i] = ptrToObjectRef[i]; - - const char* ptrToMethodRef = reinterpret_cast(&method); - for (long unsigned int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)(TypeParameter)); ++i) - str[i] = ptrToMethodRef[i - sizeof(T*)]; - - unsigned int Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)(TypeParameter))); - - DelegateDataBase* iterator = firstElement; - DelegateDataBase* temp = nullptr; - while (iterator != nullptr) - { - if (iterator->Hash == Hash) - { - if (temp != nullptr) - temp->next = iterator->next; - else - firstElement = iterator->next; - - delete static_cast*>(iterator); - break; - } - - temp = iterator; - iterator = iterator->next; - } + if (!function) + return; + + std::lock_guard lock(m_list); + std::shared_ptr old_head = list_head; + list_head = std::make_shared(function); + list_head->next = old_head; } - - void unbind(void(*func)(TypeParameter)) - { - char* str = new char[sizeof(void(*)(TypeParameter))]; - const char* ptrToFuncRef = reinterpret_cast(&func); - for (int i = 0; i < sizeof(void(*)(TypeParameter)); ++i) - str[i] = ptrToFuncRef[i]; - unsigned int Hash = FNV1a(str, sizeof(void(*)(TypeParameter))); - delete[] str; - - DelegateDataBase* iterator = firstElement; - DelegateDataBase* temp = nullptr; - while (iterator != nullptr) - { - if (iterator->Hash == Hash) - { - if (temp != nullptr) - temp->next = iterator->next; - else - firstElement = iterator->next; - - delete static_cast(iterator); - break; - } - - temp = iterator; - iterator = iterator->next; - } - } - - void Call(TypeParameter data) const + template + void unbind(std::shared_ptr object, void(Type_Object::*method)(Type_Parameter)) { - DelegateDataBase* iterator = firstElement; - while (iterator != nullptr) + std::lock_guard lock(m_list); + + if (!list_head) + return; + + if (auto object_list_data = dynamic_cast*>(list_head.get())) { - iterator->Call(data); - iterator = iterator->next; + std::shared_ptr shared_object_list_data = object_list_data->object.lock(); + if (!shared_object_list_data) + { + list_head = list_head->next; + } + else if (shared_object_list_data == object && object_list_data->method == method) + { + list_head = list_head->next; + return; + } } + + std::shared_ptr old_it = list_head, iterator = list_head->next; + while (iterator) + { + if (auto object_list = dynamic_cast*>(iterator.get())) + { + if (object_list->object.expired()) + old_it->next = iterator->next; + if (object_list->object.lock() == object && object_list->method == method) + { + old_it->next = iterator->next; + return; + } + } + old_it = iterator; + iterator = iterator->next; + } + } + + void unbind(void(*func)(Type_Parameter)) + { + std::lock_guard lock(m_list); + + if (!list_head) + return; + + if (auto function_list_data = dynamic_cast(list_head.get())) + { + if (function_list_data->function == func) + { + list_head = list_head->next; + return; + } + } + + std::shared_ptr old_it = list_head, iterator = list_head->next; + while (iterator) + { + if (auto function_list = dynamic_cast(iterator.get())) + { + if (function_list->function == func) + { + old_it->next = iterator->next; + return; + } + } + iterator = iterator->next; + } + } + + void call(Type_Parameter data) + { + std::lock_guard lock(m_list); + std::shared_ptr old_head, iterator = list_head; + while(iterator) + { + try { + iterator->call(data); + } catch (const ObjectWasDelete&) { + if (iterator == list_head) + { + list_head = list_head->next; + } + else + { + old_head->next = iterator->next; + } + } + iterator = iterator->next; + } } }; +#pragma once + + +/* + * Реализация для случая когда Type_Parameter == void + */ template<> class Delegate { - struct DelegateDataBase + class ObjectWasDelete : public std::runtime_error { - virtual ~DelegateDataBase() = default; - DelegateDataBase* next = nullptr; - long long Hash = 0; + public: + ObjectWasDelete() : std::runtime_error("Delegate (call): Object was delete") {} + }; + + /* + * Базовая структура для записи подптсок + */ + struct BaseListData + { + std::shared_ptr next; + virtual ~BaseListData() = default; virtual void call() = 0; }; - - template - struct DelegateDataForClass : DelegateDataBase - { - T* object = nullptr; - typedef void(T::*Method)(); + template + struct ObjectListData : public BaseListData + { + using Method = void(Type_Object::*)(); + std::weak_ptr object; Method method = nullptr; - - void call() override + + ObjectListData() = default; + ObjectListData(std::weak_ptr object, Method method) : object(std::move(object)), method(method) {} + void call() { - (object->*method)(); - } - }; - - struct DelegateDataForFunction : DelegateDataBase - { - typedef void(*Func)(); - Func func = nullptr; - - void call() override - { - func(); + if (auto shared_object = object.lock()) + { + (shared_object.get()->*method)(); + } + else + { + throw ObjectWasDelete(); + } } }; - DelegateDataBase* firstElement = nullptr; - - std::mutex mDelegateList; - - static constexpr unsigned int FNV1a(const char* str, unsigned int n, unsigned int hash = 2166136261U) { - return n == 0 ? hash : FNV1a(str + 1, n - 1, (hash ^ str[0]) * 19777619U); - } + struct FunctionListData : public BaseListData + { + void(*function)(); + FunctionListData() = default; + FunctionListData(void(*func)()) : function(func) {} + void call() + { + function(); + } + }; + + std::shared_ptr list_head = nullptr; + std::mutex m_list; public: - template - void bind(T* object, void(T::*method)()) + template + void bind(std::weak_ptr object, void (Type_Object::*method)()) { - char* str = new char[sizeof(T*) + sizeof(void(T::*)())]; - const char* ptrToObjectRef = reinterpret_cast(&object); - for (int i = 0; i < sizeof(T*); ++i) - str[i] = ptrToObjectRef[i]; - - const char* ptrToMethodRef = reinterpret_cast(&method); - for (int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)()); ++i) - str[i] = ptrToMethodRef[i - sizeof(T*)]; - - DelegateDataForClass* data = new DelegateDataForClass; - data->next = firstElement; - data->object = object; - data->method = method; - data->Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)())); - - delete[] str; - - mDelegateList.lock(); - firstElement = data; - mDelegateList.unlock(); + if (!object.expired() && !method) + return; + + std::lock_guard lock(m_list); + std::shared_ptr old_head = list_head; + list_head = std::make_shared>(object, method); + list_head->next = old_head; } - - void bind(void(*func)()) - { - char* str = new char[sizeof(func)]; - const char* ptrToFuncRef = reinterpret_cast(&func); - for (int i = 0; i < sizeof(void(*)()); ++i) - str[i] = ptrToFuncRef[i]; - DelegateDataForFunction* data = new DelegateDataForFunction; - data->next = firstElement; - data->func = func; - data->Hash = FNV1a(str, 8); - delete[] str; - - mDelegateList.lock(); - firstElement = data; - mDelegateList.unlock(); - } - - template - void unbind(T* object, void(T::*method)()) + void bind(void(*function)()) { - if (firstElement == nullptr) - return; - - char* str = new char[sizeof(T*) + sizeof(void(T::*)())]; - const char* ptrToObjectRef = reinterpret_cast(&object); - for (int i = 0; i < sizeof(T*); ++i) - str[i] = ptrToObjectRef[i]; - - const char* ptrToMethodRef = reinterpret_cast(&method); - for (int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)()); ++i) - str[i] = ptrToMethodRef[i - sizeof(T*)]; - - unsigned int Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)())); - - DelegateDataBase* iterator = firstElement; - DelegateDataBase* temp = nullptr; - while (iterator != nullptr) - { - if (iterator->Hash == Hash) - { - if (temp != nullptr) - temp->next = iterator->next; - else - firstElement = iterator->next; - - delete static_cast*>(iterator); - break; - } - - temp = iterator; - iterator = iterator->next; - } + if (!function) + return; + + std::lock_guard lock(m_list); + std::shared_ptr old_head = list_head; + list_head = std::make_shared(function); + list_head->next = old_head; } - - void unbind(void(*func)()) - { - char* str = new char[sizeof(void(*)())]; - const char* ptrToFuncRef = reinterpret_cast(&func); - for (int i = 0; i < sizeof(void(*)()); ++i) - str[i] = ptrToFuncRef[i]; - unsigned int Hash = FNV1a(str, sizeof(void(*)())); - delete[] str; - - DelegateDataBase* iterator = firstElement; - DelegateDataBase* temp = nullptr; - while (iterator != nullptr) - { - if (iterator->Hash == Hash) - { - if (temp != nullptr) - temp->next = iterator->next; - else - firstElement = iterator->next; - - delete static_cast(iterator); - break; - } - - temp = iterator; - iterator = iterator->next; - } - } - - void Call() const + template + void unbind(std::shared_ptr object, void(Type_Object::*method)()) { - DelegateDataBase* iterator = firstElement; - while (iterator != nullptr) + std::lock_guard lock(m_list); + + if (!list_head) + return; + + if (auto object_list_data = dynamic_cast*>(list_head.get())) { - iterator->call(); - iterator = iterator->next; + std::shared_ptr shared_object_list_data = object_list_data->object.lock(); + if (!shared_object_list_data) + { + list_head = list_head->next; + } + else if (shared_object_list_data == object && object_list_data->method == method) + { + list_head = list_head->next; + return; + } } + + std::shared_ptr old_it = list_head, iterator = list_head->next; + while (iterator) + { + if (auto object_list = dynamic_cast*>(iterator.get())) + { + if (object_list->object.expired()) + old_it->next = iterator->next; + if (object_list->object.lock() == object && object_list->method == method) + { + old_it->next = iterator->next; + return; + } + } + old_it = iterator; + iterator = iterator->next; + } + } + + void unbind(void(*func)()) + { + std::lock_guard lock(m_list); + + if (!list_head) + return; + + if (auto function_list_data = dynamic_cast(list_head.get())) + { + if (function_list_data->function == func) + { + list_head = list_head->next; + return; + } + } + + std::shared_ptr old_it = list_head, iterator = list_head->next; + while (iterator) + { + if (auto function_list = dynamic_cast(iterator.get())) + { + if (function_list->function == func) + { + old_it->next = iterator->next; + return; + } + } + iterator = iterator->next; + } + } + + void call() + { + std::lock_guard lock(m_list); + std::shared_ptr old_head, iterator = list_head; + while(iterator) + { + try { + iterator->call(); + } catch (const ObjectWasDelete&) { + if (iterator == list_head) + { + list_head = list_head->next; + } + else + { + old_head->next = iterator->next; + } + } + iterator = iterator->next; + } } }; \ No newline at end of file