question about framework code

Hi Guys,

Thanks a lot for all your hard work on this! In coordination with the book “Learn cocos2d 2” and the tutorials, I’m starting to get the hang of it. I just got the HelloCpp and TestCpp applications running on my Android tablet. This was a big step for me because I’m using Ubuntu Linux but had some build errors to sort through in Eclipse due to using a 64-bit OS. Anyhow, I’m just curious about something. I’ve seen ‘do { … some code … } while(0);’ frequently in the cocos2d framework code. Why surround code with this when it doesn’t do anything?

Cheers,
Curtis

Good question! I’m glad that you notice this.
It’s a practice of Defensive Programming

In my early projects, I used to write code like this

#check(ret)  if(!ret) goto cleanup;

bool foo(char* p1, int* p2)
{
    // local variable declaration
    bool bRet = false;  // init all local variables here, assume everything is wrong
    int*  ptr = NULL;

    PROFILER_START();

    // check input params
    check(p1 && p2);

    // start our affairs
    bRet = createSomething();
    check(bRet);   // jump to clean up phase if anything failed

    bRet = initSomething()
    check(bRet);   // the same, check it

    // the mem in heap is only alloced in some conditions
    if (cond)
    {
        ptr = (int*)mallc(123123243);  
    }
    bRet = doSomething(ptr);
    check(bRet);

    bRet = true;

cleanup: 
    // start clean up phase
    if (ptr)     
    {
        delete ptr;
        ptr = NULL;
    }

    if (!bRet)
    {
        reserveSomething();
    }
    // So we haven't missed anything until here.
    // Make sure the local variables are cleaned, especially the pointer's are deleted.

    // A function should have only one return point! 
    // In this way, it's very easy to add profiler into each function, only one line at start and one at the end.
    PROFILER_STOP();
    return bRet;
}

We have a cleanup phase and make sure each local variables are ok, they won’t make memory leak. Also make sure some must-be logics for failure will be run.
Each function has only one return point, that is very important. It will make code review easier, and adding profilers are easier too. I think no one like to add profiler like this

bool foo()
{
    PROFILER_START();

    if (condition1 && condition2)
    {
        PROFILER_STOP();
        return true;
    }
    else if (condition3)
    {
        if (condition4)
        {
            PROFILER_STOP();
            return true;
        }
        else
        {
            PROFILER_STOP();
            return false;
        }
    }
    // Are you sure you have return value for each condition cases? Code reviewer will kick your ass.
} 

So far, the defensive programming work ok in C/C++. Then we meet another problem, scripting languages has no “goto” instruction.
That’s why do {} while(0) is here. We use “break” instruction to do the job of jummping.


\#define CC\_BREAK\_IF(cond) if(!cond) break;

bool foo(char\* p1, int\* p2)
{
 bool bRet = false;
 int\* ptr = NULL;
 do
 {
 CC\_BREAK\_IF(p1 && p2);

bRet = callfunction1();
 CC\_BREAK\_IF(bRet);

ptr = (int\*)malloc(1024);
 bRet = callfunction(2);
 CC\_BREAK\_IF(bRet);

bRet = true;
 } while(0)

// cleanup here
 if (ptr)
 {
 delete ptr;
 ptr = NULL;
 }

return bRet;
}