文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-06-07 20:39

关注

在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内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯