Go语言的 defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。
典型的使用场景就是使用延迟执行语句在函数退出时释放资源。
处理业务或逻辑中涉及成对的操作是一件比较烦琐的事情,比如打开和关闭文件、接收请求和回复请求、加锁和解锁等。在这些操作中,最容易忽略的就是在每个函数退出处正确地释放和关闭资源。
C++实现延迟执行原理- 变量离开其生命周期就会被销毁。
- 类的实例在被销毁前会调用其析构函数。
- 将需要延迟执行的语句保存在类的实例中,在析构函数中调用延迟执行语句。
#pragma once template使用方法class Defer; template Defer make_defer(F f); // Defer的辅助宏定义,避免函数内多次使用defer造成变量名相同,导致编译失败。 #define DEFER_NAMELINE_CAT(name, line) name##line #define DEFER_NAMELINE(name, line) DEFER_NAMELINE_CAT(name, line) #define defer(F) auto DEFER_NAMELINE(DEFER_NAME_, __LINE__) = make_defer(F) template class Defer { public: Defer(Defer &&other) noexcept : m_func(std::move(other.m_func)) , m_invoke(other.m_invoke) { other.dismiss(); } Defer &operator=(Defer &&other) { m_func = std::move(other.m_func); other.dismiss(); } ~Defer() { if (m_invoke) { m_func(); } } void dismiss() noexcept { m_invoke = false; } // 删除拷贝构造和拷贝赋值,避免延迟语句在变量赋值后被多次调用。 Defer(const Defer &) = delete; Defer &operator=(const Defer &) = delete; private: explicit Defer(F f) noexcept : m_func(std::move(f)) { } F m_func; bool m_invoke = true; friend Defer make_defer (F); }; // Defer的辅助函数,实际构造Defer类实例的地方 template Defer make_defer(F f) { return Defer (std::move(f)); }
void complexCodeWithMultipleReturnPoints(int v)
{
// lambda表达式为需要延迟执行的语句。
// 无论函数在哪个异常分支或正常流程退出,都会执行此lambda表达式。
defer([]{ code_that_you_want_exec(); });
if (v == -1) { return;}
int v2 = code_that_might_throw_exceptions();
if (v2 == -1) { return;}
...
return;
}



