从一開始认为没有必要,到认为很好用。我经历了大概两个月的时间,以下来总结一下什么情况下使用这样的结构吧。

第一种情况:当载入文件的时候,假设载入文件失败,须要报错的时候。

当前,能够用try{}catch(){}finally{}这样的结构。可是这样做会极大的添加编译后文件的大小。使用do{}while(0)加上CC_BREAK_IF就能实现一样的效果,并且不添加文件的大小。

以下是一个样例:

bool GameScene::setScene()
{
	do{
		auto node = SceneReader::getInstance()->createNodeWithSceneFile("publish/GameScene.csb");  
		CC_BREAK_IF(!node);
		m_UI_Background->addChild(node);

		auto Checkerboard = (ComRender*)(node->getChildByTag(10009)->getComponent("GUIComponent"));
		CheckerboardUI = Checkerboard->getNode();
		//设置button
		m_btn_Setting = dynamic_cast<Button*>(CheckerboardUI->getChildByName("Button_Setting"));
		CC_BREAK_IF(!m_btn_Setting);
		//音乐button
		m_btn_Music = dynamic_cast<Button*>(CheckerboardUI->getChildByName("Button_Music"));
		CC_BREAK_IF(!m_btn_Music);
		//棋盘锁
		m_btn_Lock = dynamic_cast<Button*>(CheckerboardUI->getChildByName("Button_Lock"));
		CC_BREAK_IF(!m_btn_Lock);
		//棋盘图片
		m_Image_Checkerboard = dynamic_cast<ImageView*>(CheckerboardUI->getChildByName("Image_Checkerboard"));
		CC_BREAK_IF(!m_Image_Checkerboard);
		m_Checkerboard = Checkerboard::create(m_Image_Checkerboard);
		auto SelectPeople = (ComRender*)(node->getChildByTag(10031)->getComponent("GUIComponent"));
		SelectPeopleUI = SelectPeople->getNode();
		this->setCampBtn();

		return true;
	}while(0);
	CCLOG("ERROR:Load Resources Fail in GameScene::setScene");
	return false;
}

假设在中途出现不论什么一个变量运行后还是nullptr。那么就CC_BREAK_IF,然后显示错误日志。最后返回false给上层函数进行处理。这种处理方式是不是既优雅又方便高速,又避免了可能错误使用空指针。


另外一种情况:当不管怎样都须要在函数最后进行清理操作的时候。

以下举一个比較典型的样例,就是在函数开头声明了一个new的指针(非智能指针),依照正常的流程,须要delete。可是我们无法保证程序会不会在中途就return了,由于兴许的维护者并不知道还有这个清除操作须要运行。以下是一个对照样例:

//error
void test()
{
	GameScene* gamescene = new GameScene;
	// doSomething...
	if(gamescene->getChildByTag(111) == nullptr)
	{
		return;
	}
	// doSomething...
	delete gamescene;
	gamescene = nullptr;
}

//right
void test1()
{
	GameScene* gamescene = new GameScene;
	do{
		// doSomething...
		CC_BREAK_IF(gamescene->getChildByTag(111) == nullptr);
		// doSomething...
	}while(0);
	delete gamescene;
	gamescene = nullptr;
}

使用CC_BREAK_IF能够保证永远都会运行到最后两行,也就不会出现内存泄露。


可是这个组合也不是万能的,以下就说一个不适合这样的结构的情况吧。

当do{}while(0)的括号里存在循环的时候,就不适用这个组合了。由于break毕竟仅仅能跳出一层循环,以下是一个样例:

void test2()
{
	do{
		for(int i = 0;i <5;++i)
		{
			// doSomething...
			CC_BREAK_IF(i>4); 
			// doSomething...
		}
		CCLOG("永远显示这一行日志");
	}while(0);
}

我们希望的是,CC_BREAK_IF能跳出do{}while(0)循环。可是实际上。仅仅跳出了for循环,所以使用do{}while(0)和CC_BREAK_IF的时候,须要确保其内部不能存在其它循环,假设存在循环,还是建议使用try{}catch(){}