zhishu520 / blog

一个关于游戏开发的博客(*^__^*)
3 stars 0 forks source link

cocos2dx 源码里的那些C++技巧 #6

Open zhishu520 opened 5 years ago

zhishu520 commented 5 years ago

1. do while(0)

// 用在宏中,可以把代码都放在一个代码块里
#define CC_SAFE_DELETE(p)           do { delete (p); (p) = nullptr; } while(0)

// 出现错误情况,可以直接跳过下面的代码
bool ComponentContainer::remove(const std::string& componentName)
{
    bool ret = false;
    do 
    {        
        auto iter = _componentMap.find(componentName);
        CC_BREAK_IF(iter == _componentMap.end());

        auto component = iter->second;
        _componentMap.erase(componentName);

        component->onRemove();
        component->setOwner(nullptr);
        component->release();

        ret = true;
    } while(0);

    return ret;
 }

2. vector的swap 释放vector已经分配的内存

vector的clear函数是无法释放掉已经分配好的内存的,但是swap一个空的vector是可以做到的。

void AutoreleasePool::clear()
{
    std::vector<Ref*> releasings;
    releasings.swap(_managedObjectArray); 
    for (const auto &obj : releasings)
    {
        obj->release();
    }
}

3. DispatchGuard

利用临时变量的生命周期来更改变量,来判断函数是否还在执行。

class DispatchGuard
{
public:
    DispatchGuard(int& count): _count(count) { ++_count; }
    ~DispatchGuard() { --_count; }
private:
    int& _count;
};

void EventDispatcher::dispatchEvent(Event* event)
{
    // xxxx
    DispatchGuard guard(_inDispatch);
    // xxxx
}

4. 花里胡哨的位运算

找出比x大的2的幂次方数

int ccNextPOT(int x)
{
    x = x - 1;
    x = x | (x >> 1);
    x = x | (x >> 2);
    x = x | (x >> 4);
    x = x | (x >> 8);
    x = x | (x >>16);
    return x + 1;
}

5. 变长参数,最后一位为NULL来确定参数个数

Menu * Menu::create(MenuItem* item, ...)
{
    va_list args;
    va_start(args,item);

    Menu *ret = Menu::createWithItems(item, args);

    va_end(args);

    return ret;
}

Menu* Menu::createWithItems(MenuItem* item, va_list args)
{
    Vector<MenuItem*> items;
    if( item )
    {
        items.pushBack(item);
        MenuItem *i = va_arg(args, MenuItem*);
        while(i)
        {
            items.pushBack(i);
            i = va_arg(args, MenuItem*);
        }
    }

    return Menu::createWithArray(items);
}

6. 避免出现线程安全问题

void Scheduler::performFunctionInCocosThread(const std::function<void ()> &function)
{
    _performMutex.lock();

    _functionsToPerform.push_back(function);

    _performMutex.unlock();
}

void Scheduler::update(float dt)
{
    // xxxxxx ...
    // Testing size is faster than locking / unlocking.
    // And almost never there will be functions scheduled to be called.
    if( !_functionsToPerform.empty() ) {
        _performMutex.lock();
        // fixed #4123: Save the callback functions, they must be invoked after '_performMutex.unlock()', otherwise if new functions are added in callback, it will cause thread deadlock.
        auto temp = _functionsToPerform;
        _functionsToPerform.clear();
        _performMutex.unlock();
        for( const auto &function : temp ) {
            function();
        }
    }
}

7. C++11 智能指针的使用(shared_ptr week_ptr)

为了保证该变量在异步函数执期间不会被析构,可以传递一个指向自身的share_ptr给异步函数。

void Downloader::notifyError(ErrorCode code, const std::string &msg/* ="" */, const std::string &customId/* ="" */, int curle_code/* = CURLE_OK*/, int curlm_code/* = CURLM_OK*/)
{
    std::weak_ptr<Downloader> ptr = shared_from_this();
    Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
        if (!ptr.expired())
        {
            std::shared_ptr<Downloader> downloader = ptr.lock();
            if (downloader->_onError != nullptr)
            {
                Error err;
                err.code = code;
                err.curle_code = curle_code;
                err.curlm_code = curlm_code;
                err.message = msg;
                err.customId = customId;
                downloader->_onError(err);
            }
        }
    });
}

8. std::move 避免拷贝构造造成的浪费效率

void FileUtils::isFileExist(const std::string& filename, std::function<void(bool)> callback)
{
    auto fullPath = fullPathForFilename(filename);
    performOperationOffthread([fullPath]() -> bool {
        return FileUtils::getInstance()->isFileExist(fullPath);
    }, std::move(callback));
}