基本上我正在尝试创建一个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,从而不会释放资源。
答案 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;
});
}