defer implement for C/C++ using GCC/Clang extension

前述:

go 中defer 给出了一种,延时调用的方式来释放资源。但是对于C/C++去没有内置的这种属性。对于经常手动管理内存的C/C++有其是C程序员这种特性显得无比重要。这里给出了一种基于GCC/Clang 编译器扩展属性(cleanup)来模拟实现defer的一种方式。

头文件如下:

#ifndef __SCOPEGUARD_H__
#define __SCOPEGUARD_H__

#define __SCOPEGUARD_CONCATENATE_IMPL(s1, s2) s1##s2
#define __SCOPEGUARD_CONCATENATE(s1, s2) __SCOPEGUARD_CONCATENATE_IMPL(s1, s2)

#if defined(__cplusplus)
#include <type_traits>

// ScopeGuard for C++11
namespace clover
{
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;
};

namespace detail
{
enum class ScopeGuardOnExit
{
};

template <typename Fun>
inline ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun &&fn)
{
    return ScopeGuard<Fun>(std::forward<Fun>(fn));
}
} // namespace detail
} // namespace clover

// Helper macro
#define DEFER                                                 \
    auto __SCOPEGUARD_CONCATENATE(ext_exitBlock_, __LINE__) = \
        clover::detail::ScopeGuardOnExit() + [&]()

#elif defined(__APPLE__)
/* ScopeGuard for Objective-C */
typedef void (^ext_cleanupBlock_t)(void);
static inline void ext_executeCleanupBlock(__strong ext_cleanupBlock_t *block) { (*block)(); }
#define DEFER                                                                      \
    __strong ext_cleanupBlock_t __SCOPEGUARD_CONCATENATE(ext_exitBlock_, __LINE__) \
        __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^

#elif defined(__linux__) || defined(__ANDROID__)
#include <stdlib.h>

/**
 * Linux(HOST) GCC does not support extension 'blocks' and keyword '__strong'
 * So, just use cleanup in plain way
 */
#define ON_SCOPE_EXIT(T, V, FUNC) T *V __attribute__((cleanup(FUNC)))
#define AUTOFREE(T, V) ON_SCOPE_EXIT(T, V, __autofree)
void __autofree(void *arg)
{
    printf("in cleanup\n");
    void *ptr = *(void **)arg;
    if (ptr)
    {
        free(ptr);
    }
}
#endif

#endif //__SCOPEGUARD_H__

测试:

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

C++:

#include <iostream>
#include "scopeguard.h" using namespace std; int main() { string *as = new string("hello world!"); DEFER { 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>
#include "scopeguard.h" int main(void) { { AUTOFREE(int, pint) = (int *)malloc(4); *pint = 12; } printf("will exit in main\n"); return 0; } $ cc xx.c $ ./a.out in cleanup will exit in main

 参考:

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

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

猜你喜欢

转载自www.cnblogs.com/sinpo828/p/11672778.html