使用参数

时间:2017-07-12 21:02:54

标签: c++ c++11 lambda

基本上我正在尝试创建一个lambda来捕获一个只能移动的对象(例如unique_ptr),并将一些参数作为输入。

我有一个由回调引发的昂贵资源,我需要移动到另一个线程进行处理。该对象只能移动(并且不能更改),并且回调签名按值获取(可以更改为右值引用)。以下是状态问题的最小工作示例:

void processor(std::function<void(int)> func)
{
    auto thread = std::async(std::launch::async, func, 2);
}

using ResourceType = std::unique_ptr<int>; //Example for moveable only type

void handler(ResourceType r)
{
    processor([r](int x) // error C2280: ...unique_ptr...: attempting to reference a deleted function
    {
        int usage_of_resource = *r + x;
        std::cout << usage_of_resource << std::endl;
    });
}

我尝试过这个问题和答案(How to capture a unique_ptr into a lambda expression?) 但是,我不能使用C ++ 14,建议的答案甚至没有编译。 这就是我试过的:

std::function<void(int)> getAction(ResourceType p)
{
    return std::bind([](ResourceType& r, int x)
    { 
        int usage_of_resource = *r + x;
        std::cout << usage_of_resource << std::endl; 
    }, std::move(p), std::placeholders::_1);
}
void handler(ResourceType r)
{
    processor(getAction(std::move(r)));
}
  

g ++:错误:使用已删除的功能

     

msvc:错误:尝试引用已删除的函数

我试图创建自己的lambda(使用带有struct的{​​{1}}),但我没能解决同样的问题。最终作为一种解决方法,我创建了一个指向我的资源的新指针,并在调用处理器之前将其移动到那里,然后在我传递的lambda中提取它。

这是C ++标准的一个真正问题,只能在C ++ 14中解决吗?或者有办法以某种方式移动物体(当然最好是优雅的物体)?

修改

捕获底层资源可能会导致内存泄漏,因为处理器是一个固定大小的消息队列,当队列已满并且新元素到达时会丢弃第一个元素(出队)。因此,在捕获时间和使用时间之间,可以丢弃lambda,从而不会释放资源。

1 个答案:

答案 0 :(得分:2)

等同于移动C ++ 14的捕获是

class MyFunctor
{
public:
    MyFunctor(ResourceType res) : res(std::move(res)) {}

    void operator() (int x) const {
        int usage_of_resource = *res + x;
        std::cout << usage_of_resource << std::endl;
    }
private:
    ResourceType res;
};

并使用它:

void handler(ResourceType r)
{
    MyFunctor f{std::move(r)};
    f(42);
}

您无法使用它进行初始化std::function,因为它需要 CopyConstructible 可调用。

您可以在std::shared_ptr中换行或转移资源,将其存储在std::function中,例如:

void handler(std::unique_ptr<int> r)
{
    std::shared_ptr<int> sr = std::move(r);
    processor([sr](int x) {
        int usage_of_resource = *sr + x;
        std::cout << usage_of_resource << std::endl;
    });
}