libcurl callbacks w/c++ class members

2020-04-21 02:13发布

Taken from the libcurl programming tutorial on the libcurl site:

libcurl with C++

There's basically only one thing to keep in mind when using C++ instead of C when interfacing libcurl:

The callbacks CANNOT be non-static class member functions

Example C++ code:

class AClass 
{   
    static size_t write_data(void *ptr, size_t size, size_t nmemb,   void ourpointer)       
    {   /* do what you want with the data */   }  
}

What is this limitation for, is it a problem of scope? If each class member has it's own easy_handle then can it then use callbacks to it's own non static member functions? It doesn't go on to say. I can work with this either way, but I'm curious why it exists.

edit: One more thing; does this impose a limitation on creating easy_handle's from within a class? That would greatly pose a problem for my design if so, I'd like each object to have its own easy_handle.

标签: c++ libcurl
2条回答
姐就是有狂的资本
2楼-- · 2020-04-21 03:04

A non-static member function is normally not allowed as a C callback because it needs also the instance pointer as a hidden parameter, which is not provided by the calling C code (and this hidden parameter, depending from the compiler, may not be passed according to the "regular" calling convention, but in a particular register, ...).

Static member functions, instead, are "normal" functions with a particular scope (which is not relevant as far as the ABI is concerned).

查看更多
\"骚年 ilove
3楼-- · 2020-04-21 03:17

To call an instance method, you need an instance to call it on. The libcurl functions that take function pointers don't also take object pointers (rather, can't, since they're C functions), so there's no way of passing the requisite data to call an instance method.

You can pass an instance pointer via the userdata argument, then use that to invoke an instance method:

class AClass {
public:
    static size_t invoke_write_data
        (void *data, size_t size, size_t nmemb, void* pInstance)       
    {
        return ((AClass*)pInstance)->write_data(ptr, size, nmemb);
    }

    size_t write_data(void *data, size_t size, size_t nmemb) {
        /* ... */
    }
};

...
    extern AClass instance;

    curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, AClass::invoke_write_data);
    curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &instance);

If you need to pass more data via the userdata argument, use a struct that includes the instance pointer as a member. Be careful about memory management: the argument struct could end up leaking or being reclaimed early.

When C++0x becomes standard and supported by compilers, you should be able to make use of closures to bind an instance and instance method, passing an anonymous function as the callback.

See also: "How do I pass a pointer-to-member-function to a signal handler, X event callback, system call that starts a thread/task, etc?" from the C++ FAQ.

查看更多
登录 后发表回答