【问题标题】:Can I use libcurls CURLOPT_WRITEFUNCTION with a C++11 lambda expression?我可以将 libcurls CURLOPT_WRITEFUNCTION 与 C++11 lambda 表达式一起使用吗?
【发布时间】:2011-07-08 12:50:20
【问题描述】:

我尝试使用带有 CURLOPT_WRITEFUNCTION 的 C++11 lambda 表达式,但程序在运行时因访问冲突而崩溃。由于缺乏 C++11 知识,我不确定如何进一步研究此问题,但也许其他人知道如何完成这项工作。

功能:

#ifndef CURL_GET_H
#define CURL_GET_H

#include <curl/curl.h>
#include <curl/easy.h>
#include <vector>
#include <string>

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

错误:

Unbehandelte Ausnahme bei 0x000000cc in lpip_dl.exe: 0xC0000005: Zugriffsverletzung bei Position 0x00000000000000cc。

(位置 0x00000000000000cc 的访问冲突)

当 curl 想要使用回调时发生:

wrote = data->set.fwrite_func(ptr, 1, len, data->set.out);

【问题讨论】:

  • 你用的是什么编译器? VC++?如果是这样,VC++ 不支持隐式 lambda 到函数指针的转换(还没有?)。
  • 是的,我使用的是 VS2010 SP1。我已经注意到涉及 lambda 函数和函数指针的其他问题,但看不到与我的问题的联系。我想我只需要等待下一个 VS 版本:/ 解决方法非常......令人困惑。

标签: c++ lambda c++11 libcurl


【解决方案1】:

您实际上可以通过将 lambda 函数转换为函数指针来做到这一点。您可以先创建一个 typedef 以使投射更容易。

typedef size_t(*CURL_WRITEFUNCTION_PTR)(void*, size_t, size_t, void*);

然后你使用 static_cast。

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, static_cast<CURL_WRITEFUNCTION_PTR>(curl_callback));

注意:为了转换成C函数指针,只能使用空捕获[]。

【讨论】:

  • 我想这是一个幸运的巧合,lambda 函数类有一个函数指针作为第一个也是唯一的字段。
  • 有趣。 sizeof 空捕获的 lambda 函数为 1。而 sizeof 引用捕获的 lambda 函数为 8。
  • 我必须纠正自己。我确实查看了生成的程序集。 static_cast 不会在编译时解析,它会在运行时调用一个函数,将 lambda 转换为函数指针。
  • @AndréPuel 所有无状态 lambda 函数都有一个隐式运算符转换为函数指针。在我使用过的每个支持调用约定的编译器中,它甚至都支持转换为任意调用约定函数指针。您甚至不必显式地强制转换,您只需初始化适当类型的变量即可。强制转换是必需的,因为没有它,您会将无状态 lambda 直接粘贴到堆栈上,而不是引擎期望的函数指针。见 [stackoverflow.com/questions/25513380/c-style-callbacks-in-c11/…
【解决方案2】:

libcurl 是纯 C 库,您需要设置一个可以从此类调用的回调。这意味着有趣的 C++ 事物需要首先“C'ified”才能工作。就像变成一个老式的函数指针。

这也在 libcurl 常见问题解答条目“Using C++ non-static functions for callbacks?”中得到解决

另见:C-style Callbacks in C++11

【讨论】:

    【解决方案3】:

    这可以通过 + 前缀来完成,它返回一个 C 风格的函数指针。但这仅适用于无状态 lambda(空捕获列表,即 [])。

    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;
    };
    

    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;
    });
    

    【讨论】:

      【解决方案4】:

      在 Linux 中将 lambda 转换为正确的函数指针对我有用:

      auto curl_callback = static_cast<size_t(*)(char*,size_t,size_t,void*)>([](...){...});
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-19
        • 2012-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-01
        相关资源
        最近更新 更多