我的主题是,有时候知道一些细节会让你写出更好的代码。

============================================

之前学coocs2d-x的时候,发现有非常多do...while(0)的写法,一開始不明确为什么如此写,(起不到循环的作用),然后找了一下资料,发现这东西用处还蛮多的。如今来总结一下:

do...while(0)的妙用。

1.避免goto的使用

比方说我们须要在函数中处理一些错误。遇到错误则退出函数。当然退出之前我们须要释放一下资源。比方以下这样子:

bool HelloWorld::init()
{
// 分配资源
int *p = new int;
bool bRet = true; // 运行并进行错误处理
bRet = func1();
if(!bRet)
{
delete p;
p = NULL;
return false;
} bRet = func2();
if(!bRet)
{
delete p;
p = NULL;
return false;
} bRet = func3();
if(!bRet)
{
delete p;
p = NULL;
return false;
} // .......... // 运行成功,释放资源并返回
delete p;
p = NULL;
return true;
}

这样写最大的问题就是代码冗余。每次添加一个操作,就要处理一次,不灵活。所以这时候哦我们想到了goto,然后上面的版本号变成例如以下:

bool HelloWorld::init()
{
// 分配资源
int *p = new int;
bool bRet = true; // 运行并进行错误处理
bRet = func1();
if(!bRet) goto error; bRet = func2();
if(!bRet) goto error; bRet = func3();
if(!bRet) goto error; // 运行成功。释放资源并返回
delete p;
p = NULL;
return true; error:
delete p;
p = NULL;
return false;
}

当然,goto这东西尽管灵活方便,可是非常危急(这就跟红颜祸水这是一个意思,咦。怎么扯上这个了?)所以大部分的书籍都会建议你尽量程序中不要使用这个东西。

所以我们能够使用do...while来消除它。

例如以下:

bool HelloWorld::init()
{
// 分配资源
int *p = new int;
bool bRet = true; do
{
// 运行并进行错误处理
bRet = func1();
if(!bRet) break; bRet = func2();
if(!bRet) break; bRet = func3();
if(!bRet) break; }while(0); // 运行成功,释放资源并返回
delete p;
p = NULL;
return bRet;
}

2.宏定义中的do...while(0)

常常我们能在宏定义中看到这货的影子,比方说cocos2d-x中的

#define CC_SAFE_DELETE(p)    do { delete (p); (p) = nullptr; } while(0)

那么又没有循环,也仅仅运行了一次,这样子写有什么意义呢?

假如我们去掉do...while。例如以下:

#define CC_SAFE_DELETE(p)    delete (p); (p) = nullptr; 

if (p != NULL)
CC_SAFE_DELETE(p); //上面会转换成这样子
if (p != NULL)
delete (p);
(p) = nullptr;

如上。第二句永远运行,明显不合意思。有人可能会说,假设再加个括号呢,比方:

#define CC_SAFE_DELETE(p)    {delete (p); (p) = nullptr; }

//有可能碰到这样的情况
if (p != NULL)
CC_SAFE_DELETE(p);
else
//do else sth //上面会转换成这样
if (p != NULL)
{
delete (p);
(p) = nullptr;
};
else
//do else sth

else直接就编译错误了。

或许你会说,我们代码的习惯是在每一个推断后面加上{}, 就不会有这样的问题了,也就不须要do...while了,如:

if(...)
{
}
else
{
}

诚然,这是一个好的,应该提倡的编程习惯。可是我们须要做的是让代码具有通用性,强壮性,因此我们更提倡do...while(0)的使用方法。

========================================

转载请注明出处:http://blog.csdn.net/shun_fzll/article/details/37776429

【C++基础 03】do...while(0)妙用的更多相关文章

  1. javaSE基础03

    javaSE基础03 生活中常见的进制:十进制(0-9).星期(七进制(0-6)).时间(十二进制(0-11)).二十四进制(0-23) 进制之间的转换: 十进制转为二进制: 将十进制除以2,直到商为 ...

  2. 从零3D基础入门XNA 4.0(2)——模型和BasicEffect

    [题外话] 上一篇文章介绍了3D开发基础与XNA开发程序的整体结构,以及使用Model类的Draw方法将模型绘制到屏幕上.本文接着上一篇文章继续,介绍XNA中模型的结构.BasicEffect的使用以 ...

  3. 03、NetCore2.0下Web应用之搭建最小框架

    03.NetCore2.0下Web应用之搭建最小框架 这里我们不使用VS2017或者CLI命令的方式创建Asp.Net Core 2.0网页应用程序,而是完全手工的一点点搭建一个Web框架,以便更好的 ...

  4. day33-线程基础03

    线程基础03 6.用户线程和守护线程 用户线程:也叫工作线程,当线程的任务执行完或者通知方法结束.平时用到的普通线程均是用户线程,当在Java程序中创建一个线程,它就被称为用户线程 守护线程(Daem ...

  5. 从零3D基础入门XNA 4.0(1)——3D开发基础

    [题外话] 最近要做一个3D动画演示的程序,由于比较熟悉C#语言,再加上XNA对模型的支持比较好,故选择了XNA平台.不过从网上找到很多XNA的入门文章,发现大都需要一些3D基础,而我之前并没有接触过 ...

  6. javascript基础03

    javascript基础03 1. 算术运算符 后增量/后减量运算符 ++ ,-- 比较运算符 ( >, <, >=, <=, ==, !=,===,!== ) 逻辑运算符( ...

  7. C语言在linux内核中do while(0)妙用之法

    为什么说do while(0) 妙?因为它的确就是妙,而且在linux内核中实现是相当的妙,我们来看看内核中的相关代码: #define db_error(fmt, ...) \ do { \ fpr ...

  8. Thread.Sleep(0)妙用

    Thread.Sleep(0)妙用 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7  ...

  9. 零基础快速入门SpringBoot2.0 (一)

    零基础快速入门SpringBoot2.0 (一) 一.SpringBoot2.x依赖环境和版本新特性说明 简介:讲解新版本依赖环境和springboot2新特性概述 1.依赖版本jdk8以上, Spr ...

  10. 零基础入门 实战mpvue2.0多端小程序框架

    第1章 课程快速预览(必看!!!)在这一章节中,老师讲带领你快速预览课程整体.其中,涉及到为什么要做这么一门实战课程.制作一个小程序的完整流程是怎么样的,以及如何做项目的技术选型. 第2章 30 分钟 ...

随机推荐

  1. css样式表中的样式覆盖顺序(转)

    有时候在写CSS的过程中,某些限制总是不起作用,这就涉及了CSS样式覆盖的问题,如下 Css代码   #navigator { height: 100%; width: 200; position:  ...

  2. Laravel开启跨域的方法

    1.建立中间件Cors.php 命令:php artisan make:middleware Cors 在/app/Http/Middleware/ 目录下会出现一个Cors.php 文件. 内容如下 ...

  3. pycurl mac 安装报错Curl is configured to use SSL,

    1.使用安装第三方插件的方式安装pycurl:pip3 install pycurl 报错提示如下: Curl is configured to use SSL, but we have not be ...

  4. mysql:把DB1中A表a字段替换为DB2中B表b字段

    UPDATE DB1.A SET a = ( SELECT b FROM DB2.B WHERE B.Id = A.id) 实例: UPDATE wordpress.`wp_posts` SET po ...

  5. python 执行顺序

    从上往下顺序执行,定义的方法和类要写在调用之前, 如果有 if __name__ == '__main__'   改方法所在的文件作为启动文件时会被调用,如果作为模块被调用时不会被执行.

  6. AMQ学习笔记 - 04. 消息选择器

    概述 消息选择器使用类似于SQL语法,为Consumer指定基于Message属性的筛选条件. 消息选择器 发送的时候,给消息添加一些属性:在接收的时候,根据属性进行过滤. API javax.jms ...

  7. NOIP2011选择客栈

    n家客栈,1~n编号,每家按照某一种色调装饰,共k种,每家客栈都设有咖啡店,每家咖啡店均有各自的最低消费两位游客,要求住在颜色相同,且不是同一个客栈,在两人的客栈间选择咖啡店(包括他们住的客栈),要求 ...

  8. Apache用户目录枚举工具apache-users

     Apache用户目录枚举工具apache-users Apache服务器提供UserDir模块,允许在网站为不同的用户设置对应的目录.这样,用户可以使用http://example.com/~use ...

  9. 【数论】【筛法求素数】【欧拉函数】bzoj2818 Gcd

    gcd(x,y)(1<=x,y<=n)为素数(暂且把(x,y)和(y,x)算一种) 的个数 <=> gcd(x/k,y/k)=1,k是x的质因数 的个数 <=> Σ ...

  10. Exercise03_12

    import java.util.Scanner; public class Palindrome { public static void main(String[] args){ int a; S ...