C++ 如果给定一个像 [copy=val](){} 这样的命名捕获,lambda 浅拷贝 const Type& 会吗?

C++ Will a lambda shallow copy const Type& if it is given a named capture like [copy=val](){}?

我正在做一些需要处理多个帧的工作,我想知道 lambda 的命名按值复制语法是否会从常量引用复制数据,或者它是否会创建一个新的引用到那个数据。在我的例子中,数据在堆栈上,我需要 lambda 来保存数据的副本。

考虑经过严格编辑的代码示例

#include<functional>
#include<iostream>

struct FData
{
    int x = 5;
};

std::function<void()> test(const FData& in)
{
    return [copy = in]()
    {
        std::cout << copy.x << std::endl;
    };
}

int main()
{
    std::function<void()> callback;

    {//scoped to destroy obj1
        FData obj1;
        callback = test(obj1);
        obj1.x = 3;
    }

    {
        FData obj2;
        obj2.x = 7; //attempt to overwrite obj1 memory

        callback(); //use ?copy? of obj1 in the callback
    }

    return 0;
}

这输出了 5,所以它似乎正确地复制了数据。但是我无法通过 typeid().name() 之类的方式安全地验证类型。除了测试之外,我不确定有什么方法可以了解这一点。

Capture by value 与任何其他分配 by value 一样工作。在您的示例中,lambda 的 copy 成员将是 in 所指的 FDatacopycopy 不会引用 FDatain 本身是引用并不重要,因为 copy 不是引用。

您无需借助 RTTI 即可轻松证明这一点:

#include <functional>
#include <iostream>

struct FData
{
    int id = 1;
    int x = 5;
};

std::function<void()> test(const FData& in)
{
    return [copy = in]()
    {
        std::cout << "addr=" << &copy << " id=" << copy.id << " x=" << copy.x << std::endl;
    };
}

int main()
{
    std::function<void()> callback;

    {//scoped to destroy obj1
        FData obj1;

        std::cout << "addr=" << &obj1 << " id=" << obj1.id << " x=" << obj1.x << std::endl;

        callback = test(obj1);
    }

    {
        FData obj2;
        obj2.id = 2;
        obj2.x = 7; //attempt to overwrite obj1 memory

        std::cout << "addr=" << &obj2 << " id=" << obj2.id << " x=" << obj2.x << std::endl;

        callback();
    }

    return 0;
}

Live Demo

输出:

addr=0x7ffe23f86bb8 id=1 x=5
addr=0x7ffe23f86bb8 id=2 x=7
addr=0x7ffe23f86bc0 id=1 x=5