Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Cocos2d-x: несколько рекомендаций, как не допустить утрат памяти

Anna | 24.06.2014 | нет комментариев

Cocos2d-x — это «движок», а вернее — комплект классов, тот, что крепко упрощает разработку графических приложений для операционных систем таких как iOS, Android, Windows phone, Windows, а также для HTML 5. В различии от сocos2d-iphone, cocos2d-x полагает разработку на C , следственно он такой многофункциональный. Те, кто пишет на C знают, что каждая ответственность за выделение и освобождение памяти лежит на плечах программиста. Но разработчики cocos2d-x не нехорошо позаботились об этом и встроили в свой восхитительный движок пул объектов, тот, что полагает применение смарт-поинтеров либо, другими словами, разумных указателей.Разумный указатель содержит счетчик своих заказчиков, когда счетчик равен нулю, память, выделенная под объект, очищается. В этой статье я покажу, как верно создавать и удалять объекты в cocos2d-x, Дабы избежать утрат памяти. Все объекты классов cocos2d-x являются разумными указателями. Эту функциональность они получили от своего родителя CCObject, тот, что является исходным звеном в иерархии библиотеки классов движка.

Традиционно программист, тот, что хочет сделать объект в хипе, пишет такой код:

CMyObject* pObject = new CMyObject(); // возможен, что в CMyObject — объявлен конструктор без параметров. 

В этом случае, в памяти создается CMyObject и указатель на него помещается в переменную pObject. Позже того как pObject огромнее не необходим нужно воротить память:

delete pObject;  

Традиционно в рабочих планах создается много объектов, Зачастую не в одном модуле приложения, и нужно следить, Дабы по окончанию все они были удалены, напротив мы получаем memory leak. Дабы избежать такой неприятности, в cocos2d-x для создания объектов принято применять открытые статические функции. Исключительно когда программист расширяет функциональность классов движка, он должен придерживаться этого правила, Дабы избежать утрат памяти.
Разглядим пример создания спрайта в cocos2d-x:

...
CCSprite* pSprite = CCSprite::create(«spritename.png»); 
...

create — статическая функция — член класса CCSprite для cоздания объекта. Загляним в код этой функции:

CCSprite* CCSprite::create(const char *pszFileName)
{
    CCSprite *pobSprite = new CCSprite();
    if (pobSprite && pobSprite->initWithFile(pszFileName))
    {
        pobSprite->autorelease();
        return pobSprite;
    }
    CC_SAFE_DELETE(pobSprite);
    return NULL;
}

Вначале мы создаем объект, инициализируем его и с поддержкой кода:

pobSprite->autorelease();

добавляем в пул. Если инициализация прошла удачно, то нам вернется указатель на CCSprite, а если нет, то CC_SAFE_DELETE удалит pobSprite.
Позже выполнения этой функции, m_uReference у нашего pSprite всё еще равен нулю и жить ему осталось до выхода из локальной функции. Тут нужно быть осмотрительными: если pSprite глобальная в переделах класса, то она будет указывать на мусор. Дабы этого не случилось, нам нужно воспользоваться сделанным объектом. Скажем, добавить спрайт на слой:

pLayer->addChild(pSprite);

, либо в массив

pArray->addObject(pSprite);

и т. п. При всяком добавлении pSprite его m_uReference  будет возрастать, не непременно на 1. Это особенность реализации движка, внутри которого свои рабочие списки, массивы и т.д., они тоже влияют на m_uReference. А при всяком удалении pSprite, соответственно его m_uReference будет уменьшаться. Дозволено самим увеличивать либо сокращать m_uReference с поддержкой способов:

pSprite->retain(); // m_uReference  =1 
pStrite->release(); // m_uReference -=1

Осмотрительно пользуйтесь данными способами, всякому retain() должен соответствовать вызов release(). Иначе объект останется в памяти и произойдет memory leak.
Сейчас побеседуем о растяжении классов. Возможен, нам необходим объект, тот, что примерно как CCSprite, но с дополнительным функционалом, скажем Bonus.
Приведу пример объявления производного класса из своего плана:

class TABonus:public CCSprite
{
    TABonusType mType;
    TABonus(b2World* world, float pX, float pY,TABonusType type);
    virtual bool init();
public:
    float pBegX, pBegY;
    virtual ~TABonus();
    static TABonus* create(b2World* world, float pX, float pY,TABonusType type);
    inline TABonusType getType() {return mType;}
    void update(float pSecondElapsed);
};

Обратите внимание, конструктор объявлен в закрытой сегменты — это значит,что непосредственное создание объекта запрещено. Для этого в классе объявлена статическая функция create.
Посмотрим код функции:

TABonus* TABonus::create(b2World* world, float pX, float pY,TABonusType type)
{
   TABonus* pRet = new TABonus(world,pX,pY,type);
   if (pRet->init())
   {
     pRet->autorelease();
     return pRet;
   }
   CC_SAFE_DELETE(pRet);
   return NULL;
}

Он сходствен рассмотреному ранее. Сейчас, для создания TABonus, нужно применять дальнейший код:

TABonus* pBonus = TABonus::create(world,pX,pY, btCoins);// pBonus ->m_uReference == 0
pLayer->addChild(pBonus); //pBonus->m_uReference>0

Итог:

— Постарайтесь чураться создания объектов напрямую через оператор new, для этого используйте статические функции. Также при наследовании у производного класса нужно писать свои статические функции.
— Дабы удалить объект, нужно убрать его из всех контейнеров, куда он был добавлен, тогда m_uReference у него обнулится и память, выделенная под объект, вернется в кучу. Скажем, убрать pSprite со слоя:

pLayer->removeChild(pSprite, true);

либо из массива:

pArray->removeObject(pSprite);

— Не используйте delete для объекта сделанного в статической функции, чай помимо Вас никто не знает, что объекта огромнее нет.
— Дабы объект жил, нужно увеличить его m_uReference путем добавления в контейнер, либо вызовом retain().

Играйте по правилам и выигрывайте.

Спасибо за внимание.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB