【问题标题】:Capture moveable-only objects to lambda with parameters使用参数将可移动对象捕获到 lambda
【发布时间】:2017-12-17 11:01:30
【问题描述】:

基本上,我正在尝试创建一个 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(使用 structoperator()),但我未能解决同样的问题。最终,作为一种解决方法,我创建了一个指向我的资源的新指针,并在调用处理器之前将它移到那里,然后在我传递的 lambda 中提取它。

这是仅在 C++14 中解决的 C++ 标准的真正问题吗?还是有办法以某种方式移动对象(当然最好是优雅的)?

编辑:

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

【问题讨论】:

  • 问题似乎在于 std::bind 返回的对象如果包含std::unique_ptr 则不可移动(也不可复制)。我不知道为什么。
  • std::function&lt;void(int)&gt; 应该是 CopyConstructible

标签: c++ c++11 lambda


【解决方案1】:

相当于C++14的move capture是

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

【讨论】:

  • 正如我所写的“我试图创建自己的 lambda(使用带有 operator() 的结构),但我未能解决同样的问题”,如何你能把MyFunctor 传递给周围(例如processor)以便其他人调用它吗?
  • 正如我所说,std::function 需要 CopyConstructible 可调用,因此您不能使用给定等效项的 c++14 移动捕获 lambda。您必须将资源包装在可复制的可构造调用中。 std::shared_ptr 可能会解决这个问题。
  • Using std::shared_ptr 是我原来的 w\e,但我想避免在该流程中分配堆,所以这对我来说不是最佳解决方案。当你说“将你的资源包装在一个可复制的可构造调用中”时,你不是指MyFunctor吗??如果是这样,那么我不明白如何创建一个......
猜你喜欢
  • 2016-08-25
  • 1970-01-01
  • 2021-04-12
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 2018-05-26
  • 2018-06-08
  • 2015-12-05
相关资源
最近更新 更多