Can I use libcurls CURLOPT_WRITEFUNCTION with a C++11 lambda expression?
I tried to use a C++11 lambda expression with CURLOPT_WRITEFUNCTION, but the program crashes at runtime with an access violation. I'm not sure how to look further into this due to lack of C++11 knowledge, but maybe someone else has an idea how to make this work.
The function:
#ifndef CURL_GET_H
#define CURL_GET_H
#include <curl/curl.h>
#include <curl/easy.h>
#include <vector>
#include <s开发者_如何学编程tring>
std::vector<std::string> curl_get(const char* url)
{
CURL *curl;
CURLcode res;
std::vector<std::string> content;
auto curl_callback = [](void *ptr, size_t size, size_t nmemb, void *stream) -> size_t {
// does nothing at the moment due to testing...
return size * nmemb;
};
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/aaa.txt");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return content;
}
#endif // CURL_GET_H
The error:
Unbehandelte Ausnahme bei 0x000000cc in lpip_dl.exe: 0xC0000005: Zugriffsverletzung bei Position 0x00000000000000cc.
(Access violation at position 0x00000000000000cc)
Happens when curl wants to use the callback:
wrote = data->set.fwrite_func(ptr, 1, len, data->set.out);
You actually can do that by casting the lambda function to function pointer. You can first make a typedef to make cast easier.
typedef size_t(*CURL_WRITEFUNCTION_PTR)(void*, size_t, size_t, void*);
Then you use static_cast.
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, static_cast<CURL_WRITEFUNCTION_PTR>(curl_callback));
Note: In order to convert to C function pointer, you can only use empty captures [].
This can be done with the + prefix, which returns a C-style function pointer instead. But this only works with stateless lambdas (empty capture list i.e. []).
auto lambda = +[](void *ptr, size_t size, size_t nmemb, void *stream) -> size_t {
// does nothing at the moment due to testing...
return size * nmemb;
};
or
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, +[](void *ptr, size_t size, size_t nmemb, void *stream) -> size_t {
// does nothing at the moment due to testing...
return size * nmemb;
});
libcurl is plain C library, you need to set a callback that can be called from a such. This means funny C++ things need to be "C'ified" first to work. Like into an old-style function pointer.
This is also addressed in the libcurl FAQ entry "Using C++ non-static functions for callbacks?"
See also: C-style Callbacks in C++11
Casting the lambda to the proper function pointer works for me in Linux:
auto curl_callback = static_cast<size_t(*)(char*,size_t,size_t,void*)>([](...){...});
精彩评论