C++23中Lambda延迟执行(scopeguard)实现与标准支持问询
C++23延迟执行Lambda/Scope Guard的标准方案及你的实现分析
标准库中的类似实现
C20起标准库引入了std::scope_exit,C23将其正式纳入标准,定义在<scope>头文件中,这就是你需要的延迟执行(Scope Guard)标准实现。它的用法简洁,无需自己手写宏或类,示例如下:
#include <scope> #include <cstdio> int main() { std::scope_exit defer{[](){ puts("标准Scope Guard执行"); }}; puts("test"); }
程序会先输出test,在main函数作用域结束时执行lambda输出标准Scope Guard执行,和你的实现逻辑完全一致,且标准库已经处理了移动语义、拷贝禁用等细节。
你的实现中的明显bug
- 拷贝/移动导致重复执行:你的
DeferLambda类默认生成拷贝构造和拷贝赋值函数,拷贝后的两个对象析构时都会调用lambda;移动操作后原对象的lambda依然会被执行,这会导致同一个逻辑被重复触发。正确的做法是禁用拷贝操作,添加移动构造和移动赋值,转移lambda的所有权(比如用std::optional<T>存储lambda,移动后原对象的optional置空)。 - 缺少完美转发:
DeferLambda的构造函数以传值方式接收lambda,对于捕获大对象的lambda会产生不必要的拷贝开销。应该改用完美转发优化:template<class T> class DeferLambda { T l; public: template<class U> DeferLambda(U&& l) : l(std::forward<U>(l)) {} // 禁用拷贝 DeferLambda(const DeferLambda&) = delete; DeferLambda& operator=(const DeferLambda&) = delete; // 移动构造与赋值 DeferLambda(DeferLambda&& other) noexcept : l(std::move(other.l)) {} DeferLambda& operator=(DeferLambda&& other) noexcept { l = std::move(other.l); return *this; } ~DeferLambda() { l(); } }; auto make_defer(auto&& p) { return DeferLambda<std::decay_t<decltype(p)>>(std::forward<decltype(p)>(p)); } - 异常安全隐患:如果你的lambda执行时抛出异常,析构函数中直接调用
l()会触发std::terminate(析构函数抛出未捕获的异常会终止程序)。标准的std::scope_exit要求传入的可调用对象不抛出,你也可以在lambda内部自行捕获异常处理。 - 宏的命名冲突风险:虽然用
__LINE__生成变量名减少了冲突,但如果在同一行多次调用L宏,会生成相同的变量名,导致编译错误。标准库的实现无需依赖宏,直接声明变量即可避免这个问题。
内容的提问来源于stack exchange,提问作者Andrew Spar
相关产品推荐
相关产品推荐

