C++20前std::unique_ptr如何对lambda闭包应用EBO?
关于std::unique_ptr结合lambda删除器的空基类优化(EBO)问题
测试代码
#include <memory> #include <cstdio> int main(){ auto x1 = [](int *p){ delete(p); }; auto ptr = std::unique_ptr<int, decltype(x1)>(new int{1}, x1); printf("%zu\n", sizeof(ptr)); // 输出8,看似出乎意料 }
问题核心
测试代码中使用lambda作为删除器的std::unique_ptr实例大小为8字节,结合已知信息:
- 空基类优化(EBO)可通过继承空基类避免额外占用对象内存
- 微软STL中
std::unique_ptr通过_Compressed_pair存储删除器与指针,该类特化版本会在第一个类型为空且非final时继承它
存在疑问:C++20前lambda闭包类型无默认构造函数,继承该类型的_Compressed_pair如何实例化?std::unique_ptr又如何对闭包应用EBO?
解答
1. 核心逻辑:无需默认构造,靠拷贝构造初始化
lambda闭包类型没有默认构造函数,但**_Compressed_pair不需要默认构造它**——因为std::unique_ptr的构造是从外部传入已构造完成的lambda实例的:
- 当你调用
std::unique_ptr<int, decltype(x1)>(new int{1}, x1)时,已经把现成的lambda对象x1传给了构造函数 _Compressed_pair会通过拷贝构造来初始化继承的lambda基类部分,而不是依赖默认构造。这里的lambda是空捕获,闭包类型支持拷贝构造,完全满足需求
2. EBO的具体应用
因为当前lambda是空捕获的闭包类型,属于空类型(没有非静态数据成员),所以_Compressed_pair会触发特化逻辑,直接继承这个lambda闭包类型:
- 空基类优化生效后,继承的空类型不会占用额外内存空间
_Compressed_pair的总大小就等于存储指针的大小(64位系统下为8字节),因此整个std::unique_ptr实例的大小就是8字节
3. 关于C++20前lambda的限制
C++20前lambda确实没有默认构造函数,但这只会限制默认构造_Compressed_pair或std::unique_ptr的场景,不会影响用已存在的lambda实例进行拷贝构造的情况。而std::unique_ptr带删除器参数的构造函数,正好是用传入的删除器实例初始化内部的_Compressed_pair,完美绕开了默认构造的需求
内容的提问来源于stack exchange,提问作者Paoer111
相关产品推荐
相关产品推荐

