C ++将函数指针转换为唯一的“散列”键 [英] C++ Converting function pointer to unique “hash” key

查看:104
本文介绍了C ++将函数指针转换为唯一的“散列”键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在底部有原始问题。



我想我明白你们现在在说什么 - 因为成员函数指针的内部结构是编译器/机器具体是真的不可能做到,我试图。因此,即使它在我测试它的工作 - 我不能保证它将在其他编译器/机器。



有另一种方式去去我想要的吗?



我有一个模板类和一个基类模板类,我有一个委托类,它包含一个std :: map所有的事件委托类应该



我需要一个映射的原因是为了确保同一个成员函数(指向成员函数的事件)不会被添加一次,并且可以使用最初在实例化事件对象时使用的对象和成员函数从地图中删除事件。

 模板< class T_arg1> struct EventBase1 
{
public:
bool operator< (const EventBase1& event1)const {return _key< event1._key; };
virtual void operator()(T_arg1 t1)const {};
std :: pair< intptr_t,intptr_t> _键;
};

template< class T,class T_arg1> struct Event1:public EventBase1< T_arg1>
{
template< class T_arg1> friend class Delegate1;
typedef typename void(T :: * Method)(T_arg1);
private:
方法_method;
T * _object;
public:
Event1(T * object,Method method):_object(object),_method(method)
{
_key = std :: pair< intptr_t,intptr_t> reinterpret_cast< intptr_t>(object),reinterpret_cast< intptr_t>(reinterpret_cast< void *&>(method)
};
virtual void operator()(T_arg1 t1)const {
(_object-> * _ method)(t1);
};
};

模板< class T_arg1> class Delegate1
{
public:
typedef typename EventBase1< T_arg1> T_event;
void operator + =(T_event * observer)
{
assert(observer);
_observers [* observer] = observer;
};
void operator - =(const T_event& observer)
{
std :: map< T_event,T_event *> :: iterator i = _observers.find
if(i!= _observers.end()){
delete i-> second;
_observers.erase(i);
}
};
void operator()(T_arg1 t1)
{
for(std :: map< T_event,T_event *> :: iterator i = _observers.begin(); i!= _observers。 end(); i ++){
(*(i-> second))(t1);
}
};
private:
std :: map< T_event,T_event *> _observers;
};

原始问题



我在一个 std :: map 中存储函数指针,我生成我的地图的键如下: std :: pair< int,int>((int)((int *)object),(int)(static_cast< const void *>(& method)))
$ b

方法是一个函数(方法)指针, object 该方法的对象。



它的工作原理,但我有一个鬼祟的怀疑,我得到的第二部分的密钥是不完全正确的。



我从来没有完全理解函数指针,但我想我得到指针的地址,而不是函数的地址,编译器不会让我喜欢这个((int)(static_cast< const void *>(method)))



所以我的问题是 - 如何从函数指针获得一个唯一的键,如果我稍后从另一个函数指针指向同一个方法获得键?



提前感谢,
Martin

解决方案

第二个是不合法的:形式上,你不能转换指针到
函数到指向数据的指针(而 void * 是指向数据的指针)。
此外,你不能保证能够将任何指针转换为
int ;如果 int 至少与
指针一样大,那么转换是合法的(这意味着您的代码在大多数64
位上无法编译)系统)。



有几种方法。首先,在大多数(所有?)现代
机器上,poiters函数和指向数据的指针具有相同的
大小和表示。 (Posix需要它,事实上,即使它
不是我使用的第一个Unix机器的情况。)如果我们假设这个
,你可以通过使用 intptr_t
trick编译器使用附加级别的间接:

  std :: pair< intptr_t,intptr_t>(
reinterpret_cast< intptr_t>(reinterpret_cast< void *&>(object)),
reinterpret_cast< intptr_t>(reinterpret_cast< void *& ;>(method)))

(这假设 object 方法是指向
对象和函数的指针。)



请注意,这样做可用于指向成员函数的指针。
成员函数的指针是完全不同的野兽,我不是
认为有任何有效的方式使用它们作为一个键这种方式
(因为他们可能,并经常做,包含填充或未设置字段,在
中某些情况下)。



正式地,这不是真正保证即使对于正常
指针。该标准允许指针具有无关位,或者对于
,几个不同的指针表示来比较相等。然而,在
练习中,它在大多数(所有?)现代机器上是安全的。


Se original question in the bottom.

I think I understand what you guys are saying now – that because the internal structure of the member function pointer is compiler/machine specific it is really not possible to do that I am trying to. So even though it works when I test it – I have no guarantee that it will on other compilers/machines.

Is there another way to go about what I want then?

I have a template class and a base template class for that class, and I have a delegate class which contains a std::map of all the events the delegate class should invoke, when invoked.

The reason i need a map is, both to insure that the same member function (event pointing to member function) is not adde more that once, and to make it possible to remove events from the map using the object and member function originally used when instantiating the event object.

template <class T_arg1> struct EventBase1
{
public:
    bool operator < (const EventBase1 &event1) const { return _key < event1._key; };
    virtual void operator()(T_arg1 t1) const {};
    std::pair<intptr_t, intptr_t> _key;
};

template <class T, class T_arg1> struct Event1: public EventBase1<T_arg1>
{
    template <class T_arg1> friend class Delegate1;
    typedef typename void (T::*Method)(T_arg1);
private:
    Method _method;
    T* _object;
public:
    Event1(T* object, Method method): _object(object), _method(method)
    {
        _key = std::pair<intptr_t, intptr_t>(reinterpret_cast<intptr_t>(object), reinterpret_cast<intptr_t>( reinterpret_cast<void*&>(method)));
    };
    virtual void operator()(T_arg1 t1) const {
        (_object->*_method)(t1);
    };
};

template <class T_arg1> class Delegate1
{
public:
    typedef typename EventBase1<T_arg1> T_event;
    void operator += (T_event* observer)
    {
        assert(observer);
        _observers[*observer] = observer;
    };
    void operator -= (const T_event &observer)
    {
        std::map<T_event, T_event*>::iterator i = _observers.find(observer);
        if(i != _observers.end()) {
            delete i->second;
            _observers.erase(i);
        }
    };
    void operator()(T_arg1 t1)
    {
        for(std::map<T_event, T_event*>::iterator i = _observers.begin(); i != _observers.end(); i++) {
            (*(i->second))(t1);
        }
    };
private:
    std::map<T_event, T_event*> _observers;     
};

Original question:

I am storing function pointers in a std::map, and I am generating my key for the map as follows: std::pair<int, int>( (int)((int*)object), (int)(static_cast<const void*>(&method)) ).

method is a function (method) pointer, and object is a pointer to the object of the method.

It works, however I have a sneaky suspicion that the way I get the second part of the key isn’t entirely correct.

I have never fully understood function pointers, but I guess that I am getting the address of the pointer and not the address of the function, and the compiler won’t let me do like this ((int)(static_cast<const void*>(method))).

So my question is - how do I get a unique key from the function pointer which will the same if I later get a get the key from another function pointer pointing the same method?

Thanks in advance, Martin

解决方案

The second isn't legal: formally, you cannot convert a pointer to a function to a pointer to data (and a void* is a pointer to data). Also, you're not guaranteed to be able to convert any pointer into an int; the conversion is only legal if int is at least as large as a pointer (which means that your code should fail to compile on most 64 bit systems).

There are several ways around this. First, on most (all?) modern machines, poitners to functions and pointers to data do have the same size and representation. (Posix requires it, in fact. Even if it wasn't the case on the first Unix machines I used.) If we assume this, you can guarantee a large enough integral type by using intptr_t, and "trick" the compiler using an additional level of indirection:

std::pair<intptr_t, intptr_t>(
    reinterpret_cast<intptr_t>( reinterpret_cast<void*&>( object ) ),
    reinterpret_cast<intptr_t>( reinterpret_cast<void*&>( method ) ) )

(This supposes that object and method are your pointers to the object and the function.)

Note that this does not work for pointers to member functions. Pointer to member functions are completely different beasts, and I don't think that there is any effective way to use them as a key in this way (since they may, and often do, contain padding, or unset fields, in certain cases).

For that matter, formally, this isn't really guaranteed even for normal pointers. The standard allows pointers to have don't care bits, or for several different pointer representations to compare equal. In practice, however, it is safe on most (all?) modern machines.

这篇关于C ++将函数指针转换为唯一的“散列”键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆