cocos2d-x C++的do...while(0)另类使用方法
在C++中,有三种类型的循环语句:for, while, 和do...while, 但是在一般应用中作循环时, 我们可能用for和while要多一些,do...while相对不受重视。
但是,最近在读我们项目的代码时,却发现了do...while的一些十分聪明的用法,不是用来做循环,而是用作其他来提高代码的健壮性。
1. do...while(0)消除goto语句。
通常,如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出函数,当然,退出前先释放资源,我们的代码可能是这样:
version 1
bool Execute()
{
// 分配资源
int *p = new int;
bool bOk(true); // 执行并进行错误处理
bOk = func1();
if(!bOk)
{
delete p;
p = NULL;
return false;
} bOk = func2();
if(!bOk)
{
delete p;
p = NULL;
return false;
} bOk = func3();
if(!bOk)
{
delete p;
p = NULL;
return false;
} // .......... // 执行成功,释放资源并返回
delete p;
p = NULL;
return true; }
这里一个最大的问题就是代码的冗余,而且我每增加一个操作,就需要做相应的错误处理,非常不灵活。于是我们想到了goto:
version 2
bool Execute()
{
// 分配资源
int *p = new int;
bool bOk(true); // 执行并进行错误处理
bOk = func1();
if(!bOk) goto errorhandle; bOk = func2();
if(!bOk) goto errorhandle; bOk = func3();
if(!bOk) goto errorhandle; // .......... // 执行成功,释放资源并返回
delete p;
p = NULL;
return true; [Page] errorhandle:
delete p;
p = NULL;
return false; }
代码冗余是消除了,但是我们引入了C++中身份比较微妙的goto语句,虽然正确的使用goto可以大大提高程序的灵活性与简洁性,但太灵活的东西往往是很危险的,它会让我们的程序捉摸不定,那么怎么才能避免使用goto语句,又能消除代码冗余呢,请看do...while(0)循环:
version3
bool Execute()
{
// 分配资源
int *p = new int; bool bOk(true);
do
{
// 执行并进行错误处理
bOk = func1();
if(!bOk) break; bOk = func2();
if(!bOk) break; bOk = func3();
if(!bOk) break; // .......... }while(0); // 释放资源
delete p;
p = NULL;
return bOk; }
“漂亮!”, 看代码就行了,啥都不用说了...
2 宏定义中的do...while(0)
如果你是C++程序员,我有理由相信你用过,或者接触过,至少听说过MFC, 在MFC的afx.h文件里面, 你会发现很多宏定义都是用了do...while(0)或do...while(false), 比如说:
#define AFXASSUME(cond) do { bool __afx_condVal=!!(cond); ASSERT(__afx_condVal); __analysis_assume(__afx_condVal); } while(0)
粗看我们就会觉得很奇怪,既然循环里面只执行了一次,我要这个看似多余的do...while(0)有什么意义呢?
[NextPage]
当然有!
为了看起来更清晰,这里用一个简单点的宏来演示:
#define SAFE_DELETE(p) do{ delete p; p = NULL} while(0)
假设这里去掉do...while(0),
#define SAFE_DELETE(p) delete p; p = NULL;
那么以下代码:
if(NULL != p) SAFE_DELETE(p)
else ...do sth...
就有两个问题,
1) 因为if分支后有两个语句,else分支没有对应的if,编译失败
2) 假设没有else, SAFE_DELETE中的第二个语句无论if测试是否通过,会永远执行。
你可能发现,为了避免这两个问题,我不一定要用这个令人费解的do...while, 我直接用{}括起来就可以了 [Page]
#define SAFE_DELETE(p) { delete p; p = NULL;}
的确,这样的话上面的问题是不存在了,但是我想对于C++程序员来讲,在每个语句后面加分号是一种约定俗成的习惯,这样的话,以下代码:
if(NULL != p) SAFE_DELETE(p);
else ...do sth...
其else分支就无法通过编译了(原因同上),所以采用do...while(0)是做好的选择了。
也许你会说,我们代码的习惯是在每个判断后面加上{}, 就不会有这种问题了,也就不需要do...while了,如:
if(...)
{
}
else
{
}
诚然,这是一个好的,应该提倡的编程习惯,但一般这样的宏都是作为library的一部分出现的,而对于一个library的作者,他所要做的就是让其库具有通用性,强壮性,因此他不能有任何对库的使用者的假设,如其编码规范,技术水平等。
cocos2d-x C++的do...while(0)另类使用方法的更多相关文章
- Myeclipse 2015 stable 2.0 完美破解方法
2015-08-21 以前写了一篇<Myeclipse 2015 stable 1.0 完美破解方法>,现 在跟新一下Myeclipse 2015 stable 2.0 破解方法,此方法 ...
- Myeclipse 2015 stable 1.0 完美破解方法(转自 http://yangl.net/2015/07/14/myeclipse_2015stable_1/)
Myeclipse 2015 stable 1.0 完美破解方法 http://yangl.net/2015/07/14/myeclipse_2015stable_1/ 破解包(注册机)下载地址:链接 ...
- java ee@ Myeclipse 2015 stable 1.0 完美破解方法
Myeclipse 2015 stable 1.0 完美破解方法 破解步骤: 使用以前的注册机算号,版本选择Blue即可,后续可解锁Spring高级功能,即Bling的所有功能全部具备 1.1 进入m ...
- 使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表
原文:使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表 我们知道目标平台是32位的程序运行在64位的系统上,去访问部分注册表的时候系统自动重定向到win32node节点对应的 ...
- 转:StarUML3.0的破解方法
转自:https://blog.csdn.net/sam_shan/article/details/80585240 StarUML3.0的破解方法 最近StarUML由2.0更新到3.0.原来的破解 ...
- NAVICAT 12.0.24 连接 MYSQL8.0.12 的方法
1. 自己本机安装破解的 navicat11 结果连接不上, 所以 升级了下 navicat 12.0.24 破解方法在: https://www.jianshu.com/p/42a33b0dda9c ...
- win7系统总是安装不了net2.0的解决方法
一些网友询问说ghost win7系统总是安装不了net2.0怎么办呢?net2.0是什么?ATI显卡的控制中心 就需要在NET2.0的基础上.可是一些用户说win7系统总是安装不了net2.0如何解 ...
- N!(N的阶乘)最末位非0的求解方法
问题是求关于N!的最后一位非0位, 如3!=6,最后一位非0位为6, 5!=120, 最后一位非0位为2.怎么样快速的求出最后一位非0位呢? 最朴素的想法就是先求出N!的结果,再求出结果的最后一位非0 ...
- mysql sum 为 0 的解决方法
使用SQL语句SUM函数的时候,默认查询没有值的情况下返回的是null,而实际可能我们要用的是返回0. 解决方法:SELECT SUM(count) FROM test_table 改成: SELEC ...
随机推荐
- shell 中用管道模拟多线程
shell 中用管道模拟多线程 这里以两个例子来对比多线程和单进程 单线程的例子 # config.txt在这个例子和多线程的例子中都会用到 [root@ns_10.2.1.242 test]$ ca ...
- oracle_解锁表_解锁用户
1.解锁用户 以dba身份登录 sqlplus / as sysdba alter user scott account unlock; 2.解锁表 alter system kill ...
- ocp11g培训内部教材_053课堂笔记(043)_数据备份
053:数据库高级管理: 目录 第一部分:数据库备份与恢复... 4 第一章:备份恢复概述... 4 1.1 备份的意义: 4 1.2 数据库故障的类型:... 4 1.3 制定你的备份和恢复的计划. ...
- uva 11354 - Bond(树链拆分)
题目链接:uva 11354 - Bond 题目大意:给定一张图.每次询问两个节点路径上进过边的危急值的最大值的最小值. 解题思路:首先建立最小生成数,然后依据这棵树做树链剖分. #include & ...
- HTML解析利器-HtmlAgility学习
原文:HTML解析利器-HtmlAgility学习 HtmlAgility是一个开源的Html解析库,据说是C#版的JQuery,功能非常强大. 该篇学习它的解析功能,还可以模拟用户请求,创建html ...
- win7安装ruby on rails开发环境
前言 我们看到很多文章说ruby环境windows它是非常困难的基础上,这将是各种稀奇古怪的问题,因此,建议linux和mac发. 可是我依照教程搭了下,问题也不算太多.总过大概花费了2个半小时左右就 ...
- 为什么使用Hystrix?
分布式服务弹性框架“Hystrix”实践与源码研究(一) 文章初衷 为了应对将来在线(特别是无线端)业务量的成倍增长,后端服务的分布式化程度需要不断提高,对于服务的延迟和容错管理将面临更大挑战,公 ...
- 拥抱大家庭,nodejs走thrift
拥抱大家庭,nodejs走thrift.最贱的例子,nodejs与nodejs之间走thrift对传. 1,官网下载 http://mirrors.cnnic.cn/apache/thrift/0.9 ...
- LayOutControl
DevExpress DXperience 12.2 在 Navigation & Layout 中 有个 LayOutControl 它适用于做布局,我们普通控件 长宽 只能给固定的值,这个 ...
- MonkeyImage API 实践全记录
1. 背景 鉴于网上使用MonkeyImage的实例除了方法sameAs外很难找到,所以本人把实践各个API的过程记录下来然自己有更感性的认识,也为往后的工作打下更好的基础.同时也和上一篇文章& ...