Является ли следующее использование static_cast в конструкторе «безопасным»?
Для контекста я экспериментирую с оболочкой окна Win32, используя дизайн, основанный на политике. Часть этого включает в себя создание класса диспетчера путем наследования от базового диспетчера, содержащего карту сообщений, в функции, а затем также наследования от различных взломщиков сообщений, каждый из которых добавит один или несколько обработчиков к диспетчеру базового класса. Я хотел бы сделать это, не требуя каких-либо дополнительных подключений, то есть для каждого типа сообщения добавлять обработчики в свои собственные конструкторы, а не делать это вручную в конструкторе диспетчера.
Думаю, я прав, говоря, что Dispatcher_Base гарантированно создается до Message_Type_1 и Message_Type_2, поэтому при вызове их конструкторов static_cast вернет мне действительный объект из "этого". Однако он довольно плохо пахнет, поэтому мне интересно, не допустил ли я огромную ошибку в основной предпосылке.
#include <iostream>
#include <vector>
template<typename dispatcher_type>
class Message_Type_1
{
public:
Message_Type_1()
{
auto * dispatcher = static_cast<dispatcher_type *>(this);
dispatcher->Add_Handler(1);
}
virtual ~Message_Type_1() = default;
};
template<typename dispatcher_type>
class Message_Type_2
{
public:
Message_Type_2()
{
auto * dispatcher = static_cast<dispatcher_type *>(this);
dispatcher->Add_Handler(2);
}
virtual ~Message_Type_2() = default;
};
class Dispatcher_Base
{
public:
Dispatcher_Base()
{
}
void Add_Handler(int x)
{
listeners.push_back(x);
}
std::vector<int> const & Get_Listeners() const
{
return listeners;
}
virtual ~Dispatcher_Base() = default;
private:
std::vector<int> listeners;
};
class Dispatcher_Derived : public Dispatcher_Base,
public Message_Type_1<Dispatcher_Derived>,
public Message_Type_2<Dispatcher_Derived>
{
public:
Dispatcher_Derived() = default;
virtual ~Dispatcher_Derived() = default;
};
int main(void)
{
Dispatcher_Derived dispatcher;
auto const & listeners = dispatcher.Get_Listeners();
std::cout << "There are " << listeners.size() << " listeners in the set." << std::endl;
for (auto i : listeners)
{
std::cout << i << std::endl;
}
return 0;
}
Message_Type_1<Dispatcher_Base>
вместоMessage_Type_1<Dispatcher_Derived>
в вашем примере? - person nwp   schedule 05.02.2018static_cast
определенно является UB, потому что в конструктореMessage_Type_1
определенно еще не существует объекта типаDispatcher_Derived
, потому что для созданияDispatcher_Derived
вы должны сначала создатьMessage_Type_1
. - person nwp   schedule 05.02.2018Dispatcher_Base
существует, и именно здесь можно найти функциюAdd_Handler
. Помимо запаха кода, мне интересно, что он работает нормально как в GCC, так и в MSVC. - person Robinson   schedule 05.02.2018-fsanitize=undefined,address
, он выдастruntime error: downcast of address 0x7fffffffe540 which does not point to an object of type 'Dispatcher_Derived'
. - person nwp   schedule 05.02.2018