#c #casting
#c #Кастинг
Вопрос:
Я не уверен в этом фрагменте кода:
#include <functional>
#include <list>
#include <iostream>
void f() { std::cout << "HI!n"; }
struct fobj
{
void operator()() const { std::cout << "Bye!n"; }
};
using slot_t = std::function<void()>;
std::list<slot_t> slot_list;
template<class F>
inline std::size_t insert_slot(F f)
{
auto it = slot_list.insert(slot_list.begin(), f);
return reinterpret_cast<std::size_t>(amp;*it);
}
inline slot_tamp; recover_slot(std::size_t conn_id)
{ return *reinterpret_cast<slot_t*>(conn_id); }
int main()
{
std::size_t conn1_id = insert_slot(f);
std::size_t conn2_id = insert_slot(fobj());
recover_slot(conn1_id)(); // HI!
recover_slot(conn2_id)(); // Bye!
}
Я не вижу reinterpret_cast<T*>(some_size_t)
никаких отличий от static_cast<T*>(some_void_ptr)
, но я не совсем уверен, насколько рискованно первое.
Комментарии:
1. Это может быть немного меньше UB, если вы используете
uintptr_t
вместоsize_t
.2. На самом деле я не уверен, но
uintptr_t
существует по какой-то причине.3. UB или not…it это ужасно.
4. «Тип size_t — это определенный реализацией целочисленный тип без знака, который достаточно велик, чтобы содержать размер в байтах любого объекта». Обычно он достаточно большой, чтобы содержать адрес, но существуют архитектуры или ограничения среды, где это не выполняется. Вы могли бы добавить a
static_assert
, чтобы проверить этоsizeof(size_t) >= sizeof(amp;f)
.uintptr_t
достаточно большой, чтобы содержать адрес, но является необязательным типом, который может не предоставляться. Было бы безопаснее использовать его, а неsize_t
.5. Это явно разрешено для
reinterpret_cast
указателя на достаточно большой интегральный тип и обратно; результат гарантированно будет равен исходному указателю. Итак, предполагаяsize_t
, что он достаточно большой, или вы переключаетесь наuintptr_t
, ваш пример четко определен. Тем не менее, неясно, почему вы хотите выполнить цикл через целое число. Почему бы не обойтиslot_t*
?