Lorenz Zhao
Lorenz Zhao

Reputation: 377

Statelessly wrap a C callback interface in C++

I need to wrap a callback mechanism of a C interface statelessly in C++ accepting callables, i. e. the wrapper class shall not have any non-const members. In the C interface (not under my control) there is a function to add a callback:

void c_add_callback(void(*callback)(void* context), void* context)

Here is my attempt to wrap the C interface in a class accepting a reference to a callable:

class CppWrapper
{
public:
    // C++ callable parameter
    template<typename Function>
    void AddCallback(Function& function)
    {
        c_callbacks_.push_back
            ([](void* context)
                {
                    (*reinterpret_cast<Function*>(context))();
                }
            );
        c_add_callback
            (c_callbacks_.back()
            , reinterpret_cast<void*>(&function)
            );
    }
private:
    // storage of c callbacks
    std::list<void(*)(void*)> c_callbacks_;
};

Obviously, this approach is not stateless, as I have to store the callbacks (member c_callbacks_) as passed to the C interface, otherwise the lambdas as passed to c_add_callbacks would be temporaries and would be destructed when c_add_callback returns, see Casting a universal reference to a callable to void pointer and vice versa

Is there a way to implement the wrapper class stateless, i. e. get rid of the member?

Please see https://onlinegdb.com/rkeh-UNX0U for the full code example.

Some background: The intention to make the wrapper stateless comes from the fact that the library behind the C interface may at some point dispose all added callbacks. Obviously this would lead to an ever growing list (member c_callbacks_) when cyclically adding callbacks and triggering the library to dispose them. How can I cope with such leak if the dispose action is not propagated over the C interface?

Upvotes: 1

Views: 149

Answers (1)

MSalters
MSalters

Reputation: 179819

I'm not at all understanding what you are trying to achieve with c_callbacks_. You only use it for c_callbacks_.back(), directly after c_callbacks_.push_back()

Just use

c_add_callback([](void* context)
    {
       (*reinterpret_cast<Function*>(context))();
    },
    reinterpret_cast<void*>(&function));

Note: Like your example, this assumes the lifetime of &function is managed externally.

Upvotes: 1

Related Questions