前述:

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

头文件如下:(我只对C/C++在GCC/CLANG Linux 平台做了测试,Object-C没有测试)

#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__)) && !defined(__llvm__)
/**
* Linux(HOST) GCC does not support extension 'blocks' and keyword '__strong'
* So, just use cleanup in plain way
*/
#define DEFER(expr) \
void __SCOPEGUARD_CONCATENATE(__FUNC_, __LINE__)(void *_arg) \
{ \
(void)_arg; \
expr \
} \
int __USELESS_V __attribute__((cleanup(__SCOPEGUARD_CONCATENATE(__FUNC_, __LINE__)))); #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!");
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>
int main(int argc, char **argv)
{
{
DEFER(
printf("call defer\n");
);
printf("will quit scope\n");
}
printf("before return\n");
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

最新文章

  1. 即时搜索(input框)
  2. CoreData的使用
  3. 编写unit test以及自动化测试WebDriver
  4. 直接使用docker而无须加sudo
  5. OA项目之分页
  6. C#集合 -- 自定义集合与代理
  7. 解析PHP中的file_get_contents获取远程页面乱码的问题【转】
  8. poj2104:K-th Number
  9. 初学Android开发怎么开始?
  10. 使用Unity开发HoloLens应用
  11. SQL Server Join方式
  12. RPC和RMI的区别(Difference Between RPC and RMI)
  13. 一种基于FSIM对视频编码图像质量客观评价的方法
  14. virtualbox 提示 vboxclient the virtualbox kernel service is not running
  15. CentOS 7 服务器配置--配置iptables防火墙
  16. [oracle]解决ora-01034 oracle not available
  17. Module 3 - Azure - Web Apps
  18. .gvfs: Permission denied
  19. mybatis的0和null
  20. 2017年最新20个轻量的 JavaScript 库和插件

热门文章

  1. 题解 P1407
  2. Provisional headers are shown 问题的一种情况
  3. Mac 从睡眠恢复后没有声音的问题
  4. Kubernetes 的层级命名空间介绍
  5. pandas | DataFrame中的排序与汇总方法
  6. java反序列化——XMLDecoder反序列化漏洞
  7. Apache Cassandra 4.0新特性介绍
  8. django学习(一)
  9. 如何用VMD将轨迹文件制作动画(转载)
  10. jdk 功能变化