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

ioq*_*tix 2 c++ lambda function 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);
}
Run Code Online (Sandbox Code Playgroud)

该程序的输出是:

dup(3) = 4
close(3)
Opened path with descriptor: 4
close(4)
Run Code Online (Sandbox Code Playgroud)

我知道正在复制句柄,因为它是按照值内的值进行分配的std::function,但我在印象中std::function可能是在某些情况下分配堆,这可能会避免复制(我想这不会发生).

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

有没有办法在堆栈框架内构造句柄std::function以避免复制,还是需要采取不同的方法?

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

Vit*_*meo 5

首先,让我们解决这个问题:std::function与lambdas完全正交.我写了一篇文章,"将函数传递给函数",这些文章应阐明它们之间的关系,并说明可用于在现代C++中实现高阶函数的各种技术.

auto f =在这里使用避免了复制,但是当你需要一个函数传递给另一个函数时,这没有用.

我不同意.您可以使用模板invokefunction_view (请参阅LLVM FunctionRef用于生产就绪的实现,或者我的文章用于另一个简单的实现):

template <typename F>
void invoke(F&& function)
{
    std::forward<F>(function)();
}
Run Code Online (Sandbox Code Playgroud)

void invoke(function_view<void()> function)
{
    function();
}
Run Code Online (Sandbox Code Playgroud)