背景:我有一个场景,我必须允许在两个仿函数对象之间进行比较,使用唯一的ID来测试它们是否相等(我不能简单地检查它们的地址是否相同,如函数指针本身不存储在对象中。最初,我有这个想法,只需在0处启动id生成器并无限增加ad:
struct GenerateUniqueID{
static std::size_t id_count = 0;
auto operator()() -> std::size_t { return (id_count++); }
};
...但是,由于我每隔几秒就创建了成千上万的这些对象,我实际上设法遇到id_count溢出回0的情况!结果......令人不快。现在,我的第二个想法是,因为这些仿函数显然是函数的包装器,我可以通过将函数指针的地址转换为64位整数来执行比较,并将其存储在类中以进行比较。参见:
//psuedocode
struct Functor{
std::uint64_t id;
auto generate_id_from_function_address(function f) -> void {
id = reinterpret_cast<std::uint64_t>(&f);
}
};
现在,我的担心很简单:将函数指针转换为64位整数,表现不正常/未定义?在32位架构上?在64位架构上?在两者上?我主要关心的是虚函数,因为我知道对于内联函数,编译器只是创建一个非内联版本,所以那里没有问题。
答案 0 :(得分:2)
将常规指针(更不用说函数指针)转换为uint64_t
是实现定义的,因为指针可能比64位宽。如果您使用uintptr_t
(并且存在该类型),则转换是明确定义的。
将函数指针转换为任何整数类型是实现定义的(即使使用uintptr_t
),因为函数指针可能比常规指针更宽。像POSIX这样的其他标准明确允许这样做,因此在POSIX下,将函数指针强制转换为void*
和uintptr_t
等数据指针是安全的。
(将指向成员的指针转换为整数,数据指针或常规函数指针是未定义的,并且实际上可能总是失败,因为它们比常规指针大。)
但是,对于您的唯一ID,使用uint64_t
代替size_t
可能更简单。由于它们的范围很大,基本上不可能通过重复递增uint64_t
来溢出它。