• defer 关键字在 C/C++ 上的实现方案


    前述:

    golang 的关键字 defer 给出了一种,延时调用(RAII)的方式来释放资源。但是对于C/C++却没有内置这种方便的关键字。对于经常需要手动管理内存的C/C++尤其是C程序员这种特性显得无比重要。
    这里给出了一种 C/C++ 下模拟实现 defer 的实现方案:

    1. 针对 C 语言基于 GCC/Clang 编译器扩展属性cleanup实现
    2. 针对 C++ 利用 RAII 来实现

    头文件如下:(我只对 C/C++ 在 Linux 平台下 GCC/CLANG 编译器做了测试)

    #ifndef __SCOPEGUARD_H__
    #define __SCOPEGUARD_H__
    
    #define __SCOPEGUARD_HELPER_IMPL(s1, s2) s1##_##s2
    #define __SCOPEGUARD_HELPER(s1, s2) __SCOPEGUARD_HELPER_IMPL(s1, s2)
    
    #if defined(__cplusplus)
    #include <type_traits>
    
    // ScopeGuard for C++11
    namespace NSScopeGuard
    {
        template <typename Fun>
        class ScopeGuard
        {
        public:
            ScopeGuard(Fun &&f) : _fun(std::forward<Fun>(f)), _active(true) {}
    
            ~ScopeGuard()
            {
                if (_active)
                    _fun();
            }
    
            void dismiss() { _active = false; }
    
            ScopeGuard() = delete;
            ScopeGuard(const ScopeGuard &) = delete;
            ScopeGuard &operator=(const ScopeGuard &) = delete;
            ScopeGuard(ScopeGuard &&rhs) : _fun(std::move(rhs._fun)), _active(rhs._active) { rhs.dismiss(); }
    
        private:
            Fun _fun;
            bool _active;
        };
    
        enum class ScopeGuardEnumHelper
        {
        };
    
        template <typename Fun>
        inline ScopeGuard<Fun> operator+(ScopeGuardEnumHelper, Fun &&fn)
        {
            return ScopeGuard<Fun>(std::forward<Fun>(fn));
        }
    } // namespace NSScopeGuard
    
    // Helper macro
    #define ON_SCOPT_EXIT 
        auto __SCOPEGUARD_HELPER(RAII_AT_EXIT, __LINE__) = NSScopeGuard::ScopeGuardEnumHelper() + [&]()
    
    #elif (defined(__linux__) || defined(__ANDROID__)) && !defined(__llvm__)
    /**
     * Linux(HOST) GCC does not support extension 'blocks' and keyword '__strong'
     * So, just use cleanup in plain way
     */
    #define ON_SCOPT_EXIT(expr)                                      
        void __SCOPEGUARD_HELPER(RAII_AT_EXIT, __LINE__)() { expr; } 
        int __USELESS_VAR __attribute__((cleanup(__SCOPEGUARD_HELPER(RAII_AT_EXIT, __LINE__))));
    
    #else
    #error "platform not support!"
    #endif
    
    #endif //__SCOPEGUARD_H__
    

    测试:

    不需要过多的解释,直接看执行结果就知道了。当超出作用域(break,goto,return)之后,会自动调用指定的内存释放函数(当然这里也可以用其他函数来代替)。()

    C++:

    #include <iostream>
    #include <string>
    #include "scopeguard.h"
    using namespace std;
    
    int main()
    {
        string *as = new string("hello world!");
        ON_SCOPT_EXIT
        {
            cout << "in scope guard" << endl;
            delete as;
        };
        cout << "at end" << endl;
        return 0;
    }
    
    $ c++ xx.c
    $ ./a.out
    at end
    in scope guard
    

    C:

    #include <stdio.h>
    int main(int argc, char **argv)
    {
        {
            ON_SCOPT_EXIT(
                printf("call defern");
            );
            printf("will quit scopen");
        }
        printf("before returnn");
        return 0;
    }
    $ cc xx.c
    $ ./a.out 
    will quit scope
    call defer
    before return
    

    需要注意的是这里DEFER 宏展开后会发现,这里发生了函数的嵌套定义,经测试Clang 不支持函数嵌套定义,应次在头文件添加了对 llvm Clang独有编译器宏的判断。

    此上C代码不能在安装Clang的Linux下编译(OSX不在此考虑范围,参考头文件__APPLE__宏)

    参考:

    https://zhuanlan.zhihu.com/p/21303431

    https://zhuanlan.zhihu.com/p/35191739

  • 相关阅读:
    浅析 KMP
    【GOJ 3049】玩具
    较详细的gdb入门教程
    【GOJ 2963】记者
    【GOJ 2961】数数
    GF OIer's Talk 维护笔记
    Linux 中 UFW 的使用
    开源是什么?能吃吗?
    个人介绍
    NOIP2020 爆零记
  • 原文地址:https://www.cnblogs.com/sinpo828/p/11672778.html
Copyright © 2020-2023  润新知