defer implement for C/C++ using GCC/Clang extension
前述:
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
defer implement for C/C++ using GCC/Clang extension的更多相关文章
- c 各种编译器(gcc clang)
很多时候,出现一些类似GNU,GCC,CLANG,LLVM等与编译器有关的名词的时候,都不太清楚它到底是干嘛的,理解这些东西后, 对于xcode中很多配置型的需求修改起来都会得心应手,因此有必要了解透 ...
- CentOS安装gcc clang git mysql等软件高版本福利
最近同事需要在单位提供的开发机上临时安装gcc等软件,时间紧迫,因此向其推荐安装福利devtoolset. 感谢devtoolset,使得CentOS软件安装无比的快捷,卸载也是无与伦比的简单. gc ...
- 编译器:gcc, clang, llvm
clang Clang是LLVM的前端,可以用来编译C,C++,ObjectiveC等语言.传统的编译器通常分为三个部分,前端(frontEnd),优化器(Optimizer)和后端(backEnd) ...
- gcc/clang编译带pthread.h头文件的源码时需要的参数
今天敲了一个小程序,编译时出现错误:undefined reference pthread_create 原来由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a, ...
- clang和gcc消除警告
1. clang命令,它的作用是用来消除特定区域的clang的编译警告,-Wgnu则是消除?:警告, 例: #pragma clang diagnostic push #pragma clang di ...
- linux下Clang和gcc的区别
Clang 比 GCC 编译器的优势: 编译速度更快 编译产出更小 出错提示更友 好,比如 clang 在编译过程可以直接指出相对简单的出错位置以及它 “ 认为 ” 正确的方式 . 内置有静态分析工具 ...
- clang编译器简介
本文部分内容引用: 中文维基百科. 结构化编译器前端--clang介绍. 什么是clang编译器? clang是LLVM编译器工具集的一个用于编译C.C++.Objective-C的前端.LLVM项目 ...
- GCC编译器ABI
ABI与EABI 1)ABI(Application Binary Interface for the ARM Architecture),描述了应用程序与cpu内核的低级接口. ABI允许编译好的目 ...
- 各种GCC
Cross GCC Cygwin GCC Linux GCC MacOSX GCC MinGW GCC Solaris GCC Clang
随机推荐
- 双向BFS和启发式搜索的应用
题目链接 P5507 机关 题意简述 有12个旋钮,每个旋钮开始时处于状态 \(1\) ~ \(4\) ,每次操作可以往规定方向转动一个旋钮 (\(1\Rightarrow2\Rightarrow ...
- myBatis源码解析-类型转换篇(5)
前言 开始分析Type包前,说明下使用场景.数据构建语句使用PreparedStatement,需要输入的是jdbc类型,但我们一般写的是java类型.同理,数据库结果集返回的是jdbc类型,而我们需 ...
- python2.7用socks和socket设置代理
接下来是最近遇到的一个代理问题. 背景:一个基于python2.7的自动化测试项目 目的:因调试需求,需要通过代理连接其他公司的前端网站,来检验项目运行所在的问题. 问题:RUN>等了1分钟没有 ...
- Android CC框架中,新建组件无法显示布局问题
出错: 当在创建新的组件时,跳转到新组件成功,但是无法正确显示布局,即获取到布局文件的控件等. 原因: 当在创建新的组件时,默认生成MainActivity以及其布局activity_main.每个组 ...
- 高德地图marker事件监听-高德地图marker绑定事件就执行了[解决立即执行]
官方的demo是这样的:地址:[http://lbs.amap.com/api/javascript-api/example/infowindow/add-infowindows-to-multipl ...
- node.js03 第一个node.js程序和读取文件
Hello World 1.创建运行 创建txt文件起名为hellonode,在记事本中编写JavaScript脚本文件 例如: var bbl = 'hellonode' console.log(b ...
- 区块链入门到实战(12)之区块链 – 默克尔树(Merkle Tree)
目的:解决由于区块链过长,导致节点硬盘存不下的问题. 方法:只需保留交易的哈希值. 区块链作为分布式账本,原则上网络中的每个节点都应包含整个区块链中全部区块,随着区块链越来越长,节点的硬盘有可能放不下 ...
- C#.WinForm 拖动文件到PictrueBox(支持跨UAC拖动)
如程序以普通方式打开,那么DragDrop DragEnter 事件是可以正常使用的.但以管理员身份运行时,这两个方法将失效. 原因是 Windows机制(用户界面特权隔离). UIPI:用户界面特权 ...
- 基于 GitBook 搭建个人博客
目录 基于 GitBook 搭建个人博客 1.为什么要写博客? 2.为什么选择使用 GitBook 来搭建? 3.搭建方式 3.1 GitBook 线上直接搭建 3.2 由基于Node.js的命令工具 ...
- 外贸网站SEO优化哪家公司好
http://www.wocaoseo.com/thread-98-1-1.html 随着b2c的崛起,越来越多的企业已经放弃挂在第三方面台销售,而是选择去建独立的商场,拥有一个属于自已 ...