gpt4 book ai didi

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

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 45 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章C++实现Go的defer功能(示例代码)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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可以按如下方式来写:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func test() {
     file, err := os.Open( "test.txt" )
     if err != nil {
         return
     }
     defer file.Close()
     if ... {
         return
     }
     if ... {
         return
     }
     if ... {
         return
     }
}

只需要使用一句:

?
1
defer file.Close()

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 。

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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++示例代码可以写成:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void test()
{
     FILE * fp = fopen ( "test.txt" , "r" );
     if (nullptr == fp)
         return ;
 
     Defer d([&]()
     {
         fclose (fp);
     });
     if (...)
     {
         return ;
     }
     if (...)
     {
         return ;
     }
     if (...)
     {
         return ;
     }
}

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void test()
{
     FILE * fp = fopen ( "test.txt" , "r" );
     if (nullptr == fp)
         return ;
 
     defer( fclose (fp));
     if (...)
     {
         return ;
     }
     if (...)
     {
         return ;
     }
     if (...)
     {
         return ;
     }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#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;
}

结果如下:

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

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

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

原文链接:https://blog.csdn.net/witton/article/details/118573922 。

最后此篇关于C++实现Go的defer功能(示例代码)的文章就讲到这里了,如果你想了解更多关于C++实现Go的defer功能(示例代码)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

45 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com