c++ - 是否可以避免将参数复制到 lambda 函数?

标签 c++ function lambda c++14

我想使用 Handle 来管理文件描述符,并且我想使用 lambda 表达式来处理它们。我想使用 RAII 来管理底层文件描述符。一种选择是处理描述符的无效值(例如 -1)。但是,我希望句柄始终有效。

我发现我似乎无法避免至少调用一次复制构造函数。这是一个工作示例:

#include <fcntl.h>
#include <unistd.h>
#include <functional>
#include <system_error>
#include <iostream>

class Handle
{
public:
    Handle(int descriptor) : _descriptor(descriptor) {}
    ~Handle()
    {
        std::cerr << "close(" << _descriptor << ")" << std::endl;
        ::close(_descriptor);
    }

    Handle(const Handle & other) : _descriptor(::dup(other._descriptor))
    {
        std::cerr << "dup(" << other._descriptor << ") = " << _descriptor << std::endl;
        if (_descriptor == -1) throw std::system_error(errno, std::generic_category(), "dup");
    }

    int descriptor() const { return _descriptor; }

private:
    int _descriptor;
};

Handle open_path(const char * path)
{
    return ::open("/dev/random", O_RDONLY);
}

void invoke(std::function<void()> & function)
{
    function();
}

int main(int argc, const char * argv[]) {
    // Using auto f = here avoids the copy, but that's not helpful when you need a function to pass to another function.
    std::function<void()> function = [handle = open_path("/dev/random")]{
        std::cerr << "Opened path with descriptor: " << handle.descriptor() << std::endl;
    };

    invoke(function);
}

这个程序的输出是:

dup(3) = 4
close(3)
Opened path with descriptor: 4
close(4)

我知道句柄正在被复制,因为它是在 std::function 中按值分配的,但我的印象是 std::function 可能是堆在某些情况下分配,这可能会避免复制(我猜这并没有发生)。

有很多选项,例如堆分配,或使用已检查的标记值(例如 -1)。但是,我想要一个句柄始终有效的不变量。这是一种风格和不变量的问题。

有什么方法可以在 std::function 的堆栈帧中构造句柄以避免复制,还是我需要采取不同的方法?

也许作为附加点:我们可以在多大程度上依赖 std::function 来避免在创建时复制它的参数?

最佳答案

首先,让我们解决这个问题:std::function 与 lambda 完全正交。我写了一篇文章,"passing functions to functions"这应该阐明它们的关系并说明可用于在现代 C++ 中实现高阶函数的各种技术。

Using auto f = here avoids the copy, but that's not helpful when you need a function to pass to another function.

我不同意。您可以在 invoke 或类似 function_view 中使用模板(请参阅 LLVM 的 FunctionRef 以获得生产就绪的实现,或我的文章另一个简单的实现):

template <typename F>
void invoke(F&& function)
{
    std::forward<F>(function)();
}

void invoke(function_view<void()> function)
{
    function();
}

关于c++ - 是否可以避免将参数复制到 lambda 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44885429/

相关文章:

java - lambda 表达式是否作为接口(interface)抽象方法的实现?

lambda - 组合器在串联/默认编程语言中的作用

c++ - 我可以将多个线程分配给 OpenMP 中的一个代码段吗?

c++ - <=> 在 c++20 之前的代码中的合法出现

c - 错误 : expected '(' to follow a function. 预期为 ';'

javascript - 在 Javascript 中从字符串生成函数

function - 组合 (a -> Maybe a) 和 (an -> a) 函数

python - 使用 lambda 的递归函数,为什么这不起作用?

C++父类对齐

c++ - 屏幕截图创建和上传