为什么 C++ lambda 会导致额外调用此析构函数

Pro*_*mer 3 c++ lambda

这是程序:

#include <iostream>
#include <functional>

struct Foo
{
    inline Foo() {
        std::cout << "foo constructor" << std::endl;
    }

    inline ~Foo() {
        std::cout << "foo destructor" << std::endl;
    }
};

void NotBroken()
{
    Foo foo;
    std::function<void(Foo&)> callback;
    callback = [](auto&) { // <- notice the auto&
        std::cout << "executed callback" << std::endl;
    };
    callback(foo);
}

void TotallyBroken()
{
    Foo foo;
    std::function<void(Foo&)> callback;
    callback = [](auto) { // <- notice the auto without &
        std::cout << "executed callback" << std::endl;
    };
    callback(foo);
}

int main()
{
    NotBroken();
    std::cout << std::endl;
    TotallyBroken();
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

foo constructor
executed callback
foo destructor

foo constructor
executed callback
foo destructor
foo destructor
Run Code Online (Sandbox Code Playgroud)

从字面上看,为什么不带 & 的 auto 关键字不应该仍然检测到我将 lambda 传递到需要引用的 std::function 中?我用 MSVC、Clang 和 GCC 对此进行了测试,它们都有这种行为。

额外的析构函数调用发生在 lambda 执行结束时(仅供参考)

Mil*_*nek 7

auto其本身永远不会推导出引用类型。

你可以把你std::function::operator()想象成这样:

void operator()(Foo& f)
{
    callback(f);
}
Run Code Online (Sandbox Code Playgroud)

由于callback按值接受其参数,因此其参数的类型被推导为Foof用于初始化一个新对象,该新对象是 引用的对象的副本f。当callback结束时,该对象超出范围并被销毁。