为什么C++ lambda表达式会导致额外调用这个析构函数

piah890a  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(129)

这是程序:

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

以下是输出:

foo constructor
executed callback
foo destructor

foo constructor
executed callback
foo destructor
foo destructor

从字面上看,为什么没有&的auto关键字不应该仍然检测到我正在将lambda传递到期望引用的std::函数中?我用MSVC,Clang和GCC测试了这一点,它们都有这种行为。
额外的析构函数调用发生在lambda执行结束时

nbysray5

nbysray51#

auto本身永远不会推导出引用类型。
你可以把你的std::function::operator()想象成这样:

void operator()(Foo& f)
{
    callback(f);
}

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

相关问题