【发布时间】:2019-11-11 10:58:45
【问题描述】:
在下面的代码中,我有一个用于std::unique_ptr 的自定义删除器(使用通过引用捕获的 lambda)。我预计std::unique_ptr 对象的大小应该与默认删除器(即使用运算符删除)的大小相同,因为捕获是通过引用进行的。我知道无状态函子和 lambdas(没有捕获)不会产生大小损失,那么为什么 lambdas 引用捕获会产生大小损失?提前感谢您的解释。
#include <iostream>
#include <memory>
class X{};
int main()
{
// custom deleter using a state-full lambda
double data[100]{0};
auto lmb_sf = [&data](X* ptr){
// do something
std::cout<<"In custom deleter using a state-full lambda\n";
delete ptr;
};
std::unique_ptr<X,decltype(lmb_sf)> ptr_sf(new X, lmb_sf);
std::cout<<"Size of ptr_sf = "<<sizeof(decltype(ptr_sf))<<"\n";
return 0;
}
按引用捕获输出(即使用 ... lmb_sf = [&data] ...)
Size of ptr_sf = 16
In custom deleter using a state-full lambda
按值捕获输出(即使用 ... lmb_sf = [data] ...)
Size of ptr_sf = 808
In custom deleter using a state-full lambda
【问题讨论】:
-
Lambda 捕获基本上是作为编译器生成的 closeure 类的私有成员创建的。
-
引用不是魔术。它需要存储空间,在 lambda 内部。
-
@Sepel 引用不是需要存储的。这里的参考没有被优化掉。 (这种优化是可能的,但通常代价高昂。)
-
其实除了
sizeof结果外,unique_ptr实例的大小与内联后生成的代码无关。然而,sizeof类型的结果(具有外部链接)在大多数实现中受 ABI 要求支配,编译器需要在内部有效地将正在使用的实际类型转换为私有克隆(没有其他观察者行为更改)表示。这项工作需要证明转换的正确性(主要是根据没有额外特定知识的 as-if 规则),这通常很困难且不值得。
标签: c++ lambda c++14 unique-ptr