Now, I have a problem with lambdas, as you can see in the codes below, if this pointer ( the HelloWorld node) destroy, the code in lambdas will crash the app.
Could I solve this problem with std::shared_ptr? Could someone give me some suggestions regarding this problem? Thanks,
bool HelloWorld::init()
{
if ( !Scene::init() )
{
return false;
}
auto visibleSize = Director::getInstance()->getVisibleSize();
auto origin = Director::getInstance()->getVisibleOrigin();
auto label = Label::createWithTTF("Hello World", "fonts/arial.ttf", TITLE_FONT_SIZE);
label->setPosition(Vec2::ZERO);
this->addChild(label, 1);
auto downloader = new (std::nothrow) network::Downloader();
downloader->setOnTaskError([this](const network::DownloadTask& task, int error_code, int error_internal_code, const std::string& error_string) {
});
downloader->onTaskProgress = [this](const network::DownloadTask& task,int64_t /*bytesReceived*/,int64_t totalBytesReceived, int64_t totalBytesExpected) {
};
downloader->onDataTaskSuccess = [this,label,origin,visibleSize](const cocos2d::network::DownloadTask& task, std::vector<unsigned char>& buffer) {
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]() {
//the "this" pointer destroyed before that lambda is invoked.
//so the app will crash here
if (auto image = utils::findChild<ui::ImageView*>(this, "image")) {
image->loadTexture("test.png");
}
//same with above
if(label) {
label->setPosition(origin.x + visibleSize.width/2,origin.y + visibleSize.height - label->getContentSize().height);
}
});
};
}
If your object, HelloWorld, is being destroyed, then the downloader object should also be destroyed, correct? Downloader does not inherit from CC:Ref, so you’re responsible for release memory associated with it.
A possible solution is to make downloader a member variable of HelloWorld, and in the destructor of “HelloWorld”, free it. You may need to set all download callbacks to nullptr before you free it as well.
Make cocos2d::network::Downloader a smart pointer to simplify things (in HelloWorld.h):
You may need a lock on it, but I’m not entirely sure. The reason being that the callbacks may trigger while it’s in the middle of the destructor, before it clears the callback pointers.
Since this is the only open smart pointer topic, and it might be useful to the author or anybody else. I would like to share a couple of classes that make std smart pointers out of Ref objects.
I know that there is a Cocos solution in CCRefPtr.h. And thanks to developers for that!
But there may be cases when you need to use the STL smart pointers.
So here are the implementations:
Code
template <class RefType, class SmartPtrType>
SmartPtrType MakeSmartPtr(RefType* refObj)
{
auto result = SmartPtrType(refObj, [](RefType* innerPtr) { if (innerPtr) innerPtr->release(); });
if (result)
result->retain();
return result;
}
template <class RefType>
std::shared_ptr<RefType> MakeSharedPtr(RefType* refObj)
{
return MakeSmartPtr<RefType, std::shared_ptr<RefType>>(refObj);
}
template <class T>
using UniquePtr = std::unique_ptr<T, std::function<void(T*)>>;
template <class RefType>
UniquePtr<RefType> MakeUniquePtr(RefType* refObj)
{
return MakeSmartPtr<RefType, UniquePtr<RefType>>(refObj);
}
I don’t think that description is needed here. It looks pretty self-explanatory. But if anyone has a problem understanding this, let me know.
In my next post, I will demonstrate the use of the classes.