C++实现Go的defer功能(示例代码)

 更新时间:2021年07月11日 09:39:47   作者:witton  
defer和go一样都是Go语言提供的关键字。defer用于资源的释放,会在函数返回之前进行调用。接下来通过本文给大家介绍C++实现Go的defer功能,感兴趣的朋友跟随小编一起看看吧

在Go语言中有一个关键字:defer,它的作用就是延迟执行后面的函数,在资源释放方面特别有用,比如下面一段C/C++的示例代码:

void test()
{
	FILE* fp = fopen("test.txt", "r");
	if (nullptr == fp)
		return;

	if (...)
	{
		fclose(fp);
		return;
	}
	if (...)
	{
		fclose(fp);
		return;
	}
	if (...)
	{
		fclose(fp);
		return;
	}
	fclose(fp);
}

在每一处返回之前都需要调用fclose来关闭文件句柄,中间的流程中断越多,越是容易遗漏调用fclose导致未正常关闭文件。

C++可以使用shared_ptr,auto_ptr之类的智能指针来管理分配的内存,但是像上面这种情况C++并没有现成的可使用的代码来处理。而Go语言提供了defer关键字来解决此类问题,Go可以按如下方式来写:

func test() {
	file, err := os.Open("test.txt")
	if err != nil {
		return
	}
	defer file.Close()
	if ... {
		return
	}
	if ... {
		return
	}
	if ... {
		return
	}
}

只需要使用一句:

defer file.Close()

即可,Go会自动在return之后调用defer后面的函数。我们再看看下面的示例:

package main

import (
	"fmt"
)

func test() (n int, err error) {
	defer fmt.Println("测试1")
	defer fmt.Println("测试2")
	defer fmt.Println("测试3")
	return fmt.Println("test")
}

func main() {
	test()
}

它的输出为:

test
测试3
测试2
测试1

在这里插入图片描述

可以看出有多个defer时,按照先进后出的方式执行的。

C++中我们可以利用析构函数来实现,而且C++的局部变量析构规则也是按照先进后出的方式执行的。为此,我们需要定义一个Defer类:

#include <functional>
typedef std::function<void()> fnDefer;
class Defer
{
public:
	Defer(fnDefer fn) : m_fn(fn)
	{
	}
	~Defer()
	{
		if(m_fn)
			m_fn();
	}
private:
	fnDefer m_fn;
};

这样,前面的C++示例代码可以写成:

void test()
{
	FILE* fp = fopen("test.txt", "r");
	if (nullptr == fp)
		return;

	Defer d([&]()
	{
		fclose(fp);
	});
	if (...)
	{
		return;
	}
	if (...)
	{
		return;
	}
	if (...)
	{
		return;
	}
}

不用再在每一处返回前手动写代码关闭文件了。

但是这里还有一点不便之处就是需要手写一个lambda表达式和手动定义一个变量,这个很好解决,使用宏来处理。

#define defer1(a,b) a##b
#define defer2(a, b) defer1(a, b)
#define defer(expr) Defer defer2(__Defer__,__COUNTER__) ([&](){expr;})

为了方便在同一函数多处使用,定义了defer宏来给变量命不同的名,前面的代码可以改为:

void test()
{
	FILE* fp = fopen("test.txt", "r");
	if (nullptr == fp)
		return;

	defer(fclose(fp));
	if (...)
	{
		return;
	}
	if (...)
	{
		return;
	}
	if (...)
	{
		return;
	}
}

这样就实用且方便得多了。下面给出完整代码以及测试用例:

#include <functional>

using namespace std;

typedef std::function<void()> fnDefer;
class Defer
{
public:
	Defer(fnDefer fn) : m_fn(fn)
	{
	}
	~Defer()
	{
		if(m_fn)
			m_fn();
	}
private:
	fnDefer m_fn;
};

#define defer1(a,b) a##b
#define defer2(a, b) defer1(a, b)
#define defer(expr) Defer defer2(__Defer__,__COUNTER__) ([&](){expr;})

class Test
{
public:
	void f(int i)
	{
		printf("f:%d %p\n", i, this);
	}
};

int main(int argc, char *argv[])
{
	Test t;
	printf("test:%p\n", &t);
	defer(t.f(1));
	defer(t.f(2));
	defer(t.f(3));

	return 0;
}

结果如下:

在这里插入图片描述

以上在VC 2015以及GCC、Clang下测试通过。

到此这篇关于C++实现Go的defer功能(示例代码)的文章就介绍到这了,更多相关Go关键字defer内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • C语言数字图像处理之直方图均衡化

    C语言数字图像处理之直方图均衡化

    这篇文章主要为大家详细介绍了C语言数字图像处理之直方图均衡化,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • C语言实现数据结构串(堆分配存储表示法)实例详解

    C语言实现数据结构串(堆分配存储表示法)实例详解

    这篇文章主要介绍了C语言实现数据结构串(堆分配存储表示法)实例详解的相关资料,需要的朋友可以参考下
    2017-07-07
  • c++项目构成从cmake使用基础详解

    c++项目构成从cmake使用基础详解

    这篇文章主要为大家介绍了c++项目构成,从cmake使用基础开始为大家讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • 一文带你了解Qt中槽的使用

    一文带你了解Qt中槽的使用

    这篇文章主要为大家详细介绍了Qt中槽的使用教程,文中的示例代码讲解详细,对我们学习Qt有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12
  • C语言实现小型电子词典

    C语言实现小型电子词典

    这篇文章主要为大家详细介绍了C语言实现小型电子词典,用户可以进行英译汉、汉译英等功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • C++的内联函数你了解吗

    C++的内联函数你了解吗

    这篇文章主要为大家详细介绍了C++的内联函数,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C语言安全之数组长度与指针实例解析

    C语言安全之数组长度与指针实例解析

    这篇文章主要介绍了C语言安全之数组长度与指针,需要的朋友可以参考下
    2014-07-07
  • C语言用数组实现反弹球消砖块

    C语言用数组实现反弹球消砖块

    这篇文章主要为大家详细介绍了C语言用数组实现反弹球消砖块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C++ OpenGL实现三角形的绘制

    C++ OpenGL实现三角形的绘制

    这篇文章主要主要为大家详细介绍了如何利用C++和OpenGL实现三角形的绘制,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手尝试一下
    2022-06-06
  • C++常用函数总结(algorithm 头文件)

    C++常用函数总结(algorithm 头文件)

    本文给大家详细介绍了algorithm 头文件中最常用的函数及其使用方法,当然这只是其中的一部分,algorithm 头文件中还有很多其他的函数,感兴趣的朋友一起看看吧
    2023-12-12

最新评论