为何将捕获型lambda赋值给std::function会导致更多拷贝?
为什么初始化std::function时拷贝构造调用次数比auto多?
我们拆解两种初始化场景的底层逻辑:
auto初始化的情况
当你写auto f = [a1](){};时:
- 首先构造一个lambda闭包对象,按值捕获
a1会触发一次A的拷贝构造(把a1复制到闭包对象的内部成员中)。 - 用这个临时闭包对象初始化
f时,编译器会启用返回值优化(RVO)——直接将临时对象的内存内容复用给f,不需要再调用闭包对象的拷贝构造(自然也不会再触发A的拷贝构造)。所以最终只输出1次CC。
哪怕你直接写[a1](){};(不赋值给变量),也只是创建临时闭包对象时触发一次拷贝,之后临时对象销毁,没有额外操作,同样只输出1次CC。
std::function初始化的情况
当你写function<void()> f = [a1](){};时,std::function是一个类型擦除的通用函数包装器,它的工作机制和原生lambda类型完全不同:
- 同样先构造临时lambda闭包对象,捕获
a1触发第一次A的拷贝构造。 std::function需要将这个闭包对象存储到自己的内部存储中(可能是栈上的小对象缓冲区,也可能是堆内存),这个过程必须调用闭包对象的拷贝构造函数。而闭包对象的拷贝构造会递归调用其内部A成员的拷贝构造,于是就触发了第二次CC。
额外说明
如果你的A类定义了移动构造函数(比如A(A&&) = default;),那么第二次操作会变成移动构造,不会触发拷贝构造的输出。但因为你的代码里只定义了拷贝构造,所以只能走拷贝逻辑。
内容的提问来源于stack exchange,提问作者Gonen I
相关产品推荐
相关产品推荐

