C++实现defer声明方法详解

 更新时间:2022年11月16日 11:43:21   作者:程序员~彭国庆  
这篇文章主要介绍了C++实现defer声明,在和朋友交谈时候,无意间了解到Go语言的defer,发现挺有意思的。和智能指针类似,当出了作用域后,被defer修饰的操作才会执行

本文代码地址:https://github.com/pengguoqing/samples_code

一、前言

   在Go 语言里面有一个 defer 声明, 它的作用是将函数调用保存在列表中, 函数返回时依次调用列表中的函数。

之前实现简易版的智能指针文章中指出, 智能指针内部就是利用的 RAII特点, 将对象的声明周期使用栈来管理。 因此可以借鉴 Go语言中的 defer逻辑, 然后结合RAII的特点来实现一个 C++ 版本的 defer, 依次来实现在当前作用域内必须要调用的函数。

  关于离开作用域时某些函数必须调用的一个经典例子就是文件的关闭, 如下:

	FILE *file = fopen("readme.ext", "rb");
	if (file == NULL) 
	{
		return;
	}
	if (caseOne)
	 {
		// dosomething
		fclose(file); // 必须手动关闭文件
		return;
	}
	//caseTwo
	//dosomething
	fclose(file);     // 必须手动关闭文件
	return;

   这种情况下需要显示的在多个 return 的之前调用 fclose(file)关闭文件, 一方面维护的时候可能会忘记关闭文件, 而且代码看起来也不够简洁。熟悉 RAII 技术后, 常用的方式是实现一个相关 scope 类封装, 在文件开发成功后将 FILE 句柄传入构造函数,在离开作用域时利用栈资源销毁调用 scope 类的析构函数 关闭文件。这当前时一种解决方案, 但是每当遇到一个这种场景时就需要手动封装一个相关的 scope 类。所以需要一个 类似 defer的东西方便使用。

二、实现

2.1 相关技术

①编译器类型自动推导;

②Lambda表达式(仿函数);

③RAII;

④转发引用

2.2 实现

  对函数调用只需要一次, 所以需要类似 unique_ptr的方式, 管理仿函数对象的类只能被移动, 不能被拷贝和赋值,声明如下:

public:
	inline CXDeferImpl(const Functor& functor);
	inline CXDeferImpl(Functor&& functor);
	inline CXDeferImpl(CXDeferImpl&& another);
	inline ~CXDeferImpl();
private:
	//不允许拷贝, 赋值
	CXDeferImpl(const CXDeferImpl& another)			  = delete;
	CXDeferImpl operator=(const CXDeferImpl& another) = delete;
	CXDeferImpl operator=(CXDeferImpl&& another)	  = delete;

类成员只需要一个仿函数对象和一个是否有效的标志:

private:
    Functor  m_func;
    bool     m_valid;

2.3 对外接口

  以宏的方式对外提供调用, 利用 Lambda表达式封装需要调用的函数,毕竟它的内部就是一个实现仿函数的类, 再让编译器自动推导 Lambda 类型来构造一个 CXDeferImpl实例, 每次 defer() 声明都创建一个对象 CXDeferImpl。

#define CONCAT_(a, b, c) a##b##c
#define CONCAT(a, b, c)  CONCAT_(a, b, c)
#define defer(x) \
  auto CONCAT(defer_, __LINE__, __COUNTER__) = MakeDeferIns([&]{x;})

三、测试

  当然是是用万能并且经典的 “Hello world!” 了, 哈哈哈。测试其离开作用域时能不能完整的输出的 “Hello world!”, 代码如下:

void TestDefer()
{
  defer(cout<<"world!"<<endl);
  cout<<"Hello ";
}
void TestDefer2()
{
  {
      defer(TestDefer());
      cout<<"Test defer in scope"<<endl;
  }
  cout << "Test defer are ok?" << endl;
  defer(cout<<"TestDefer2"<<endl);
}
void TestDefer3(int a)
{
  {
      defer(cout << "test param func " << a << endl);
  }
  defer(cout << "TestDefer3" << endl);
}
int main()
{
  TestDefer2();
  TestDefer3(100);

  return 0;
}

输出如下:

到此这篇关于C++实现defer声明方法详解的文章就介绍到这了,更多相关C++ defer内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • C++结构体中变长数组的使用问题分解刨析

    C++结构体中变长数组的使用问题分解刨析

    变长数组在C++中指的是集合(也叫容器)如vector就是C语言中,所有的数组都不定长,没有下标越界的概念,数组实质就是一个指针(由数组名充当)因此C语言中数组的长度没有任何意义平常在C语言中讲的不定长数组,其实就是指针
    2022-08-08
  • C语言实现模拟USB对8bit数据的NRZI编码输出

    C语言实现模拟USB对8bit数据的NRZI编码输出

    今天小编就为大家分享一篇关于C语言实现模拟USB对8bit数据的NRZI编码输出,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C语言联合体Union特点及运用全面讲解教程

    C语言联合体Union特点及运用全面讲解教程

    这篇文章主要为大家介绍了C语言联合体Union特点及运用的全面讲解教程有需要深度朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2021-10-10
  • C语言使用openSSL库AES模块实现加密功能详解

    C语言使用openSSL库AES模块实现加密功能详解

    这篇文章主要介绍了C语言使用openSSL库AES模块实现加密功能,详细分析了C语言加密的相关概念、原理及AES模块加密具体实现技巧,需要的朋友可以参考下
    2017-05-05
  • C语言实现扫雷游戏(可展开)

    C语言实现扫雷游戏(可展开)

    这篇文章主要为大家详细介绍了C语言实现扫雷游戏,实现扫雷展开和提醒,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • 探讨:C++实现链式二叉树(用非递归方式先序,中序,后序遍历二叉树)

    探讨:C++实现链式二叉树(用非递归方式先序,中序,后序遍历二叉树)

    本篇文章是对用C++实现链式二叉树(用非递归方式先序,中序,后序遍历二叉树)的方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 深入了解C语言指针

    深入了解C语言指针

    这篇文章主要介绍了C语言指针详解及用法示例,介绍了其相关概念,然后分享了几种用法,具有一定参考价值。需要的朋友可以了解下
    2021-07-07
  • c++入门必学库函数sort的基本用法

    c++入门必学库函数sort的基本用法

    Sort函数包含在头文件为#include<algorithm>的c++标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可,下面这篇文章主要给大家介绍了关于c++入门必学库函数sort的基本用法,需要的朋友可以参考下
    2022-11-11
  • 解读C++编程的相关文件操作

    解读C++编程的相关文件操作

    这篇文章主要介绍了解读C++编程的相关文件操作,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • 使用C++中的ADO对SQLite进行增删改查

    使用C++中的ADO对SQLite进行增删改查

    本文将介绍如何使用C++的ADO (ActiveX Data Objects)对SQLite数据库进行增删改查操作,文中有详细的代码示例,需要的朋友可以参考下
    2023-06-06

最新评论