前述:

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. List 集合的操作

    如果当前id存在集合里  去除当前id   如果不在集合里   去除集合最后一个结果Long videoId = 0l; // 当前 IDList<VideoZoneReturnBean> ...

  2. 【原创】Linux虚拟化KVM-Qemu分析(一)

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...

  3. Java callback回调

    package com.callback; public interface CSCallBack { public void process(String status); } package co ...

  4. 机器学习:支持向量机(SVM)

    SVM,称为支持向量机,曾经一度是应用最广泛的模型,它有很好的数学基础和理论基础,但是它的数学基础却比以前讲过的那些学习模型复杂很多,我一直认为它是最难推导,比神经网络的BP算法还要难懂,要想完全懂这 ...

  5. badger 一个高性能的LSM K/V store

    原文:https://colobu.com/2017/10/11/badger-a-performant-k-v-store/ github地址:https://github.com/dgraph-i ...

  6. SpringBoot集成Swagger2,3分钟轻松入手!

    一.引入maven <dependency> <groupId>io.springfox</groupId> <artifactId>springfox ...

  7. 关闭jetbrains ide support 正在调试此浏览器提示

    1 安装JetBrains IDE Support插件 插件地址 2 启用插件 3 设置访问端口 4 WebStorm中设置Live Edit 5 关闭"JetBrains IDE Supp ...

  8. 【Flutter 实战】自定义动画-涟漪和雷达扫描

    老孟导读:此篇文章是 Flutter 动画系列文章第五篇,本文介绍2个自定义动画:涟漪和雷达扫描效果. 涟漪 实现涟漪动画效果如下: 此动画通过 CustomPainter 绘制配合 Animatio ...

  9. 如何通过seo技术提高网站对用户的友好度

    http://www.wocaoseo.com/thread-129-1-1.html    今天的天气又是29度,眼看着满大街的人都穿着短袖和衬衣了,自己也再不能穿个厚厚的外套出去了,要不会被别人笑 ...

  10. Android,java,php开发最基本的知识,mysql sqlite数据库的增删改查代理,sql语句

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985转载请说明出处. 下面是代码: 增加:insert into 数据表(字段1,字段2,字段3) valu ...