微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

转让所有权时按值捕获 Lambda

如何解决转让所有权时按值捕获 Lambda

我有一个 RAII 风格的类来管理某些资源的所有权。因此,显式删除了复制构造函数和赋值运算符,仅存在移动变体,它们移动资源并使源(引用)无效。到目前为止,它运行良好,但现在我想将这种对象移动到在其他地方处理的 std::function 中,以便该对象成为所有权载体,并最终释放该对象。幸运的是,C++14 允许在按值捕获的同时使用移动赋值,所以它看起来像是要走的路。类似的东西:

std::function<void()> act = [temp = move(resCarrier),description]() mutable {
    try {
// hopefully exception-safe
        auto c = make_unique<DataProcessor>(move(temp),description);
        c->doStuff();
    }  catch (...) {}
};
scheduler->RunLater(move(act));

但没那么容易。它应该工作,但它没有。出现乱七八糟的模板错误,最终以这种方式结束(为了清楚起见略有缩短)。

/usr/include/c++/10/bits/std_function.h:161:6: error: use of deleted function ‘<WHOLE SIGNATURE OF CURRENT FUNCTION>::<lambda()>&)’
...
note: ‘<WHOLE SIGNATURE OF CURRENT FUNCTION>::<lambda()>&)’ is implicitly deleted because the default deFinition would be ill-formed:
   99 |   std::function<void()> act = [temp = move(resCarrier),description]() mutable
      |                                                                    ^
...
error: use of deleted function ‘TResCarrier::TResCarrier(const TResCarrier&)’

所以看起来编译器基本上忽略了移动语义,并在捕获 lambda 声明中的变量时坚持使用复制构造函数。到目前为止,我无法说服它以不同的方式处理它。到目前为止,“最好”的想法是围绕携带的对象创建一个级别的重定向,以便它可以通过值进行复制和捕获(例如围绕资源的 shared_ptr)。但这将是没有充分理由的运行时开销。

我是否忽略了某些东西,或者在 std::function 后面是否存在隐藏的令人讨厌的类型擦除限制或 lambda 到函数映射的限制?

解决方法

lambda 不是 std::function

你是对的,c++14 允许将某些东西移动到 lambda 中,甚至在之后移动所说的 lambda。

另一方面,std::function 要求可调用对象是可复制构造和可复制分配的。

来自cppreference

类模板 std::function 是一个通用的多态函数包装器。 std::function 的实例可以存储、复制和调用任何 CopyConstructible Callable 目标——函数、lambda 表达式、绑定表达式或其他函数对象,以及指向成员函数的指针和指向数据成员的指针。

存储的可调用对象被称为 std::function 的目标。如果 std::function 不包含目标,则称其为空。调用空 std::function 的目标会导致抛出 std::bad_function_call 异常。

std::function 满足 CopyConstructible 和 CopyAssignable 的要求。

可能的解决方案的一些想法可能是:

  • 创建您自己的函数包装器(或使用库)来支持仅移动可调用项。

  • 将您的 std::unique_pre 包裹在 std::shared_ptr 中并捕获它。

第一个选项似乎更强大,但只是为了展示快速变通的想法。

#include <memory>
#include <functional>

int main() {
    auto moveonly = std::make_unique<int>(5);
    auto wrapped = std::make_shared<std::unique_ptr<int>>(std::move(moveonly));

    auto lam = [wrapped]() {
        return *(*wrapped);
    };

    std::function<int()> f = lam;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。