1

Considering the following code (see https://rextester.com/OAWUM62639):

#include <iostream>
#include <functional>

void foo( int x_ )
{
    std::cout<< "Value: " << x_ << "\n";
}

void something( void *c )
{
    auto *f = static_cast<std::function<void()>*>(c);
    (*f)();
}

int main()
{
    int x = 2;
    
    std::function<void()> lmbd = [=](){ foo(x); }; // lambda with capture.
    
    something( &lmbd ); // is this implicit conversion safe?
}

Is the implicit conversion from a std::function<void()> to a void* safe?

The code seems to be running as expected, but I am not sure about the underlying rules that the C++11 standard imposes in such situations.

A similar question is this one here: How do I pass a std::function object to a function taking a function pointer?, but the accepted answer suggests using a reinterpret_cast. Is the reinterpret_cast a necessity in this case (see https://rextester.com/ZUY69757)?

10
  • 2
    This is conversion from std::function<void()> * to a void *, and yes, it is safe. Also accepted answer in related question correctly states that it is not possible to pass ::std::function instead of pointer to function. Commented Aug 23, 2024 at 15:51
  • No the lambda in main has captures, so it is NOT convertible to a function pointer. And casting to void* in C++ is definitely not good practice and in this case not safe because the lambda isn't a (function) pointer but an object Commented Aug 23, 2024 at 15:55
  • @PepijnKramer No one mentioned conversion of lambda. Commented Aug 23, 2024 at 15:58
  • 4
    @ConstantinosGlynos the capturing vs non-capturing issue would only apply if you were passing the lambda itself to something() as a C-style function pointer. But you are not doing that, so the issue is moot. You are wrapping the lambda inside of a std::function object, and then passing an object pointer to something(). ANY object pointer can safely be converted to a void* and then back to the original object. Commented Aug 23, 2024 at 17:04
  • 1
    @Constantinos Glynos "something is a C function. " -- how is "something" a C function if it converts void* to std::function*? Dou you mean C++ function with C-linkage? Commented Aug 23, 2024 at 18:00

1 Answer 1

3

Is the implicit conversion from a std::function<void()> to a void* safe?

All of the shown code is safe.

In general, for any object of type T it is completely fine to convert a pointer to it to void* and then static_cast it back to T* to then use it.

The tricky bits about such an interface are:

  1. Casting to void* loses type information, but you must cast back to the exact original type to use the pointed-to object. Casting to any other type will likely end in undefined behavior. So, usually the only reasonable behavior for such an interface is to only copy the pointer value itself and pass the pointer back to context provided by the user, which knows the actual type.

  2. You lose any ownership semantics. The void* pointer is always purely observing. It doesn't carry any ownership. Therefore the caller has to make sure that the actual object (i.e. lmbd) outlives any use of the void* pointer by something. If something stores the pointer somewhere for e.g. a later callback, that can become tricky.

These kind of interfaces are sometimes necessary when interacting with C, but for pure C++ code there is no need to do it this way. Templates or passing std::function directly are superior solutions.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this clear explanation. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.