前述:

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的更多相关文章

  1. c 各种编译器(gcc clang)

    很多时候,出现一些类似GNU,GCC,CLANG,LLVM等与编译器有关的名词的时候,都不太清楚它到底是干嘛的,理解这些东西后, 对于xcode中很多配置型的需求修改起来都会得心应手,因此有必要了解透 ...

  2. CentOS安装gcc clang git mysql等软件高版本福利

    最近同事需要在单位提供的开发机上临时安装gcc等软件,时间紧迫,因此向其推荐安装福利devtoolset. 感谢devtoolset,使得CentOS软件安装无比的快捷,卸载也是无与伦比的简单. gc ...

  3. 编译器:gcc, clang, llvm

    clang Clang是LLVM的前端,可以用来编译C,C++,ObjectiveC等语言.传统的编译器通常分为三个部分,前端(frontEnd),优化器(Optimizer)和后端(backEnd) ...

  4. gcc/clang编译带pthread.h头文件的源码时需要的参数

    今天敲了一个小程序,编译时出现错误:undefined reference pthread_create 原来由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a, ...

  5. clang和gcc消除警告

    1. clang命令,它的作用是用来消除特定区域的clang的编译警告,-Wgnu则是消除?:警告, 例: #pragma clang diagnostic push #pragma clang di ...

  6. linux下Clang和gcc的区别

    Clang 比 GCC 编译器的优势: 编译速度更快 编译产出更小 出错提示更友 好,比如 clang 在编译过程可以直接指出相对简单的出错位置以及它 “ 认为 ” 正确的方式 . 内置有静态分析工具 ...

  7. clang编译器简介

    本文部分内容引用: 中文维基百科. 结构化编译器前端--clang介绍. 什么是clang编译器? clang是LLVM编译器工具集的一个用于编译C.C++.Objective-C的前端.LLVM项目 ...

  8. GCC编译器ABI

    ABI与EABI 1)ABI(Application Binary Interface for the ARM Architecture),描述了应用程序与cpu内核的低级接口. ABI允许编译好的目 ...

  9. 各种GCC

    Cross GCC Cygwin GCC Linux GCC MacOSX GCC MinGW GCC Solaris GCC Clang

随机推荐

  1. for语句——猜数字

    #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib. ...

  2. 很挫的 SHFileOperation 用法 2011-07-18 11:42

    今天编写一个局域网文件拷贝的demo .其中有一个 SHFileOperation 的用法,这个函数有个参数SHFILEOPSTRUCT.查看msdn有如下解释: pFromAddress of a ...

  3. windows 服务端 狼人杀 发牌器 开发完成 待继续开发其他服务

    开发工具: python2.7 eric4 成果链接地址 https://wws.lanzous.com/iPCDTfnuoif

  4. python 在目标位置建立文件夹

    import os path = r'D:\pywork\12' # 指定位置 if not os.path.exists(path + '/' + '任务集'): #如果目标位置 不存在该文件夹“任 ...

  5. android.content.res.Resources$NotFoundException: String resource ID #0xb

    原代码: protected void convert(BaseViewHolder helper, Student item) { helper.setText(R.id.item_tv_realm ...

  6. Socket原理及实践(Java/C/C++)

    原理 基本概念 什么是TCP/IP.UDP? 详细的可以看一下这个:学习计算机网络知识只要一篇就够了! TCP/IP(Transmission Control Protocol/Internet Pr ...

  7. autotools使用

    autotools制作makefile 下面以hello.c来说明生成makefile的过程. 基本步骤如下: 1)autoscan命令生成configure.scan文件,重命名configure. ...

  8. 七夕节表白3d相册制作(html5+css3)

    七夕节表白3d相册制作 涉及知识点 定位 阴影 3d转换 动画 主要思路: 通过定位将所有照片叠在一起,在设置默认的样式以及照片的布局,最后通过设置盒子以及照片的旋转动画来达到效果. 代码如下: &l ...

  9. 牛客网数据库SQL实战解析(21-30题)

    牛客网SQL刷题地址: https://www.nowcoder.com/ta/sql?page=0 牛客网数据库SQL实战解析(01-10题): https://blog.csdn.net/u010 ...

  10. 使用tess4j完成身份证和营业执照图片的文字识别

    这两天研究了一下关于OCR图文解析的技术.当然市场上已经有开源服务,比如百度的AI开放平台,就有OCR相关的API接口.我这里选用的是Tesseract开源框架,java封装版本是tess4j.结合网 ...