Can I convert a pointer to member function to a char array and back using reinterpret_cast?

StackOverflow https://stackoverflow.com/questions/14899730

  •  09-03-2022
  •  | 
  •  

문제

I have some code that looks like this:

char member_data[16];

template<typename T>
void set(void (T::*member)(void)) {
    memcpy(member_data, (char*) &member, sizeof(member));
}

template<typename T>
void (T::*)(void) get() {
    void (T::*member)(void);
    memcpy((char*) &member, member_data, sizeof(member));
    return member;
}

In the full context, I can be sure that set always uses the same type as the following get.

Can this be safely rewritten to use reinterpret_cast?

Edit:

Does this code do the same thing as above?

char member_data[16];

template<typename T>
using member_func = void (T::*)();

template<typename T>
void set(member_func<T> member) {
    reinterpret_cast<member_func<T>&>(member_data) = member;
}

template<typename T>
member_func<T> get() {
    return reinterpret_cast<member_func<T>&>(member_data));
}

Seems to work

도움이 되었습니까?

해결책

The version you have in your edited part is not valid: you can't access an arbitrary char array as any other type. It may be possible to achieve something like this in a valid way by using std::aligned_storage<..> instead of a plain char array.

If member_data is declared as

std::aligned_storage<sizeof(member_func<T>), alignof(member_func<T>)>::type member_data;

or (essentially equivalently)

alignas(member_func<T>) char member_data[sizeof(member_func<T>)];

then your reinterpret_cast<..> approach should actually work. Instead of the template parameter dependent sizeof and alignof expressions, you can try using any fixed member_func<some_class>. It is highly unlikely that an implementation has different size or alignment requirements for pointers to member functions of different classes. If you want to be really safe use static asserts to check.

Can this be safely rewritten to use reinterpret_cast?

Other than what is described in your edit, you can directly cast a member function pointer, like reinterpret_cast<SomeType>(member), only, if SomeType is also a pointer-to-member type. So you can choose one pointer-to-member function type as "generic member function pointer storage", if all you do with that value is to convert it back to the original member pointer type.

You can't convert a pointer to member into a pointer to object (or vice versa).

In both cases your code is unsafe as is, because it will overrun the member_data buffer, if sizeof (void (T::*)()) > 16.

And by the way: the first code example already does use reinterpret_cast: The old-style cast to (char*) from void (T::**)() already is equivalent to a reinterpret_cast ;-)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top