千家信息网

C++如何实现Go的defer功能

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,本篇内容介绍了"C++如何实现Go的defer功能"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在G
千家信息网最后更新 2025年12月02日C++如何实现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 mainimport (        "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 typedef std::function 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 using namespace std;typedef std::function 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", i, this);        }};int main(int argc, char *argv[]){        Test t;        printf("test:%p", &t);        defer(t.f(1));        defer(t.f(2));        defer(t.f(3));        return 0;}

结果如下:

"C++如何实现Go的defer功能"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0