в чем смысл цикла bool bRet do while в cocos2d-X?

Я новичок в Cocos2D-X, но программирую довольно давно... Мне было интересно, в чем смысл этого кода:

моя путаница в основном связана с этой частью:

логический bRet = ложь; сделать { } пока (0)

вот весь метод, чтобы дать некоторый контекст:

  bool GameScene::init()
    {
        CCLog("GameScene::init");
    bool bRet = false;
    do 
    {
        //////////////////////////////////////////////////////////////////////////
        // super init first
        //////////////////////////////////////////////////////////////////////////
        CC_BREAK_IF(! CCLayer::init());

            // Initialize the parent - gets the sprite sheet loaded, sets the background and inits the clouds
            MainScene::init();

            // Start off as game suspended
            gameSuspended = true;

            // Get the bird sprite
            CCSprite *bird = CCSprite::createWithSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("bird.png"));
            this->addChild(bird, 4, kBird);

            // Initialize the platforms
            initPlatforms();

            // Create the bonus sprite
            CCSprite *bonus;

            // Load in the bonus images, 5, 10, 50, 100
            for(int i=0; i<kNumBonuses; i++) 
            {
                    bonus = CCSprite::createWithSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(bonus_image[i]));
                    this->addChild(bonus,4, kBonusStartTag+i);
                    bonus->setVisible(false);
            }

            // Create the Score Label
            CCLabelBMFont* scoreLabel = CCLabelBMFont::labelWithString("0",  "Images/bitmapFont.fnt");
            this->addChild(scoreLabel, 5, kScoreLabel);

            // Center the label
            scoreLabel->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width/2,CCDirector::sharedDirector()->getWinSize().height - 50));

            // Start the GameScene stepping
            schedule(schedule_selector(GameScene::step));

            // Enable the touch events
            setTouchEnabled(true);
            // Enable accelerometer events
            setAccelerometerEnabled(true);

            // Start the game
            startGame();

    bRet = true;
} while (0);

return bRet;
}

этот код взят из: https://code.google.com/p/tweejump-cocos2dx/source/browse/trunk/Classes/GameScene.cpp

это игра с открытым исходным кодом.

Я понимаю, что bRet означает возвращаемое значение bool, но я запутался в нескольких вещах... Одна из причин, по которой меня это смущает, заключается в том, почему даже такая программа? во-вторых, как цикл while узнает, когда bRet == false, если он просто равен 0... я что-то упустил?

Мой другой вопрос: как узнать, когда использовать синтаксис CCdataType* varName = ..., по сравнению с CCdataType *pVarName = ... Я знаю, что второй - это указатель, но, возможно, я что-то упускаю... Я не понимаю разницы. первое заявление почтения?


person AlexW.H.B.    schedule 11.03.2013    source источник
comment
Это весь код? do { }while(0) - нет - кажется, чего-то не хватает.   -  person Voo    schedule 12.03.2013
comment
нет, я использовал его в качестве примера, обычно там много всего... Обычно это метод scene::init()... Я просто пропустил его, потому что он может быть двусмысленным... Я cocos2d -X, глядя на игры с открытым исходным кодом, и я видел это во многих из них.   -  person AlexW.H.B.    schedule 12.03.2013


Ответы (3)


В вашем примере отсутствует важная часть, которая все объясняет - реальная логика в коде. Я не эксперт по Cocos, но, насколько я вижу, он обычно используется следующим образом:

bool bRet = false;
do 
{
    CC_BREAK_IF(!conditionA); // same as  if (!conditionA) break;
    ... some code which possibly sets bRet
    CC_BREAK_IF(!conditionB);        
    ... some other code which possibly sets bRet
    CC_BREAK_IF(!conditionC);        
    ... some other code which possibly sets bRet
    bRet = true;
} while (0);
return bRet;

в этом случае он позволяет коду переходить к оператору return без необходимости прибегать к goto или вкладывать набор операторов if. Сравните это с этим:

bool bRet = false;
if (conditionA); 
{
    ... some code which possibly sets bRet
    if (conditionB)
    {
        ... some other code which possibly sets bRet
        if (conditionC);        
        {
            ... some other code which possibly sets bRet
        }
    }
}
bRet = true;

return bRet;
person Zdeslav Vojkovic    schedule 11.03.2013
comment
о, это имеет больше смысла... инструкция wile прерывается, если CC_Break_If возвращает 0? - person AlexW.H.B.; 12.03.2013

Я нашел обоснование на форуме Cocos2d-x.

Ранее разработчик Cocos2d-x написал код, который управлял очисткой с помощью gotos:

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

void func()
{
  bool bRet = false;

  bRet = doSomething();
  check(bRet);
  bRet = doSomethingElse();
  check(bRet);

  bRet = true;

cleanup:
  // Do clean up here

  return bRet;
}

Как видите, это действительно неприятный способ перейти к очистке в конце функции, если что-то пойдет не так. Каждый вызов функции возвращает результат, был ли он успешным или нет. Затем используется макрос check, чтобы узнать, верно ли bRet, а если нет, сразу переходит к метке cleanup.

Затем он решил избавиться от goto и заменить его на break из цикла do while:

#define CC_BREAK_IF(cond)  if(!cond) break;

void func()
{
  bool bRet = false;

  do {
    bRet = doSomething();
    CC_BREAK_IF(bRet);
    bRet = doSomethingElse();
    CC_BREAK_IF(bRet);

    bRet = true;
  } while (0);

  // Do clean up here

  return bRet;
}

Это имеет точно такой же эффект. Он просто использует break как механизм goto для перехода к коду после цикла do while.

person Joseph Mansfield    schedule 11.03.2013
comment
Сравните это с моим переписыванием якобы проблемного кода: gist.github.com/LearnCocos2D/5139277 не нужны странные языковые конструкции, такие как do/while(0) - person LearnCocos2D; 12.03.2013

Нет смысла, это просто плохой стиль. Весь метод можно (и нужно) переписать так:

bool GameScene::init()
{
    CCLog("GameScene::init");

    if (!CCLayer::init())
        return false;

    // Initialize the parent - gets the sprite sheet loaded, sets the background and inits the clouds
    MainScene::init();

    // … lots of scene setup code here ...

    return true;
}

Я видел похожий код, в котором движок выполняет свой основной цикл, но в этом случае это будет бесконечный цикл:

do
{
    // run game loop as fast as it can

    // end the game
    if (userQuits)
        break;
} while(true);

Даже если вам нужна дополнительная область видимости, например, чтобы избежать конфликтов имен локальных переменных, пары дополнительных фигурных скобок будет достаточно. Вот так:

{
    int x = 10;
    // do stuff
}
{
    int x = 234; // this x is in its own scope
    // do other stuff
}
person LearnCocos2D    schedule 12.03.2013
comment
Если вам нужно много очищающего кода, делать это по-своему означает множество дублирования. Тем не менее, gotos в c - разумный способ справиться с очисткой, в C++ есть RAII. - person Voo; 12.03.2013
comment
Что нужно будет дублировать? Несколько случаев, когда init может завершиться ошибкой и должен будет вернуть false? В этом случае, если уже есть макрос CC_BREAK_IF, может быть и макрос CC_RETURN_FALSE_IF. ;) - person LearnCocos2D; 12.03.2013
comment
Если не просто return false; а вместо doStuff1(); doStuff2(); return false; - то придется постоянно дублировать вызовы doStuffX. В C++ вы можете использовать RAII, чтобы избежать всей проблемы вместе, в C у вас может быть много вложенных ifs, но решение goto/break является хорошо известным решением этой проблемы и используется, например. также в ядре линукса. - person Voo; 12.03.2013
comment
@LearnCocos2D Многим людям не нравится иметь несколько операторов возврата. - person Zdeslav Vojkovic; 12.03.2013
comment
Я тоже, за исключением возврата как можно раньше в верхней части функции. Я вижу, что эта проблема усугубляется более сложным кодом, но на самом деле она не должна засорять код там, где он не нужен. И, учитывая пример на форуме cocos2d-x, я не понимаю, почему он не переписывается с использованием if/else и возвращаемого значения, установленного в true только тогда, когда все условия (инициализация, создание, выделение чего-либо) выполнены успешно. ИМХО, так чище и легче читать. - person LearnCocos2D; 12.03.2013
comment
Просто чтобы показать, что я имею в виду, я переписал псевдокод с форума cocos2d-x в том стиле, который буду использовать. Эта проблема, которую пытается решить код do/while/breakif, даже не существует. gist.github.com/anonymous/5139243 - person LearnCocos2D; 12.03.2013
comment
@LEarncocos2D Вероятно, согласованность. Использование одного метода во всем коде имеет свои преимущества по сравнению с использованием двух разных версий. Люди, работающие над кодом, будут знакомы с этой идиомой, и она действительно не вносит никаких уловок или сложностей (тем не менее, goto cleanup чище и проще для понимания). - person Voo; 13.03.2013