C++20中使用std::bit_cast创建闭包(lambda)对象是否合法?
答案
核心结论
该程序语法上符合C++标准的良构要求,编译器无需输出任何诊断信息,但它的运行行为是未定义行为,这种通过std::bit_cast手动构造lambda闭包的方式不具备标准层面的合法性,不可在生产环境中依赖。
编译通过的原因
std::bit_cast的合法使用需要满足两个强制要求:
- 源类型和目标类型都必须是*可平凡复制(TriviallyCopyable)*类型
- 源类型和目标类型的大小完全相等
示例中的lambda仅捕获了一个A*指针,由于指针是可平凡复制类型,该闭包的默认拷贝/移动构造、赋值运算符、析构函数都是平凡实现,因此闭包类型本身满足可平凡复制的要求。在当前主流编译器的实现中,仅捕获单个指针的闭包大小和指针大小完全一致,因此std::bit_cast调用满足所有语法层面的要求,编译可以正常通过。
未定义行为的根源
C++标准从未对lambda闭包的内存布局做出任何强制性约定:
- 标准没有规定捕获的成员在闭包内部的存储顺序、偏移量
- 标准没有禁止闭包类型在捕获成员之外添加任何隐含的额外字段
- 标准没有保证仅捕获一个指针的闭包大小等于指针的大小
你现在看到的运行结果完全依赖于当前编译器的非标准实现约定:仅捕获单个指针的lambda会将该指针作为唯一的成员存储在偏移为0的位置,没有额外字段,大小和指针完全一致。这种约定没有任何标准背书,只要编译器调整闭包布局(比如加入调试标识、类型信息字段等),程序的运行结果就会完全不可预期,甚至直接崩溃。
即使当前编译器实现符合你的预期,这种写法也属于标准未定义的范畴,没有任何合法性。
正确替代方案
如果需要绕开getter()的异常限制构造对应的可调用对象,正确的做法是显式定义可公开构造的自定义函数对象替代lambda,保证内存布局完全可控,不要使用这种hack实现。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

