I’d like to share some c++11 grammar sugar I create in my project.
* cc::create
namespace cc {
template
T* create(Args&& ...args) {
auto pRet = new T();
if (pRet && pRet->init(std::forward(args)...)) {
pRet->autorelease();
return pRet;
}
delete pRet;
return nullptr;
}
}
cc::create<T> can support init(...) functions with any args, you don’t need the CREATE_FUNC macro in your CustomNode anymore. Just provide the init(...) functions, and when instancing, use:
auto node = cc::create(...)
* cc::unique_ptr
namespace cc {
template
using unique_ptr = std::unique_ptr>;
template
unique_ptr make_unique(T *ptr) {
if (ptr) ptr->retain();
auto deleter = [](void *p) {
auto ptr = static_cast(p);
if (ptr) ptr->release();
};
return unique_ptr(ptr, deleter);
}
}
cc::unique_ptr<T> is a smart pointer for CCObject, it can cope with STL containers. We don’t need to manually retain&release anymore. For example, CCObject as a class member can be more easier:
# in xx.h
private:
cc::unique_ptr _objects;
# in xx.cpp
bool CustomNode::init() {
_objects = cc::make_unique(CCArray::createWithCapacity(objectCount));
...
}
Thanks. With which compilers did you test this? Do you enable c11 only for your project, not cocos2d-x? AFAIK cocos2d-x is unable to compile with c11 support ATM.
Yes, a traditional handmade smart pointer with the overloaded operator T*() function is easier when work with cocos2dx.
I enable c11 for cocos2dx project. Clang and g both support c11 now.
for XCode project:
<pre>
Build Settings -> C Language Dialect choose C11 > C*+ StandardLibrary choose libc*+
</pre>
for android project with android-ndk-r8b:
<pre>
addstd=gnu0x to the APP_CPPFLAGS in jni/Application.mk
Did you try msvc? There was mentioned here on forums some time ago that cocos2d-x can’t be compiled with c++11 support. Here’s issue I’ve found: https://github.com/cocos2d/cocos2d-x/issues/1313. Maybe some work was done since then.
Could you tell us what version of XCode that you’re using? And how about the IOS deployment target version?
I’m using XCode 4.5.2 and my deployment target is IOS 5.1 but I’m still failed to compile it.
Thanks,
Terry.
EDIT:
Ok, I finally figure out how to solve it. It’s because I’m using cocos2d-x as a separate project so I also have to set cocos2d-x project to use c**11 as you mentioned it.
Le Yang wrote:
Yes, a traditional handmade smart pointer with the overloaded operator T*() function is easier when work with cocos2dx.
>
I enable c**11 for cocos2dx project. Clang and g*+ both support c*+11 now.
>
for XCode project:
[…]
>
for android project with android-ndk-r8b:
[…]
I’ve been doing this kind of stuff too. Haven’t tried working in Visual Studio but cocos2d-x v2.0.2 builds fine in Xcode version 4.5.2 with C11 as the language dialect modulo a bunch of warnings — this is to iOS6, not sure if that matters but I doubt it. Has anyone tried building with C11 to Android?
Le Yang, why even bother calling autorelease(), retain() and release() if you are using std smart pointers? I just use standard smart pointers and don’t use the cocos2dx pool allocator stuff at all for objects in the CCNode hierarchy. The only minor difficulty with working this way is that all of the builtin creation functions call autorelease() on the created object so you have to make your own versions that don’t do this i.e. you have to make a version of createWithSpriteFrameName(), for example, that doesn’t call autorelease().
Beyond being more idiomatic C++ I think handling sprite memory this way is probably more efficient. I say “probably” because I don’t totally understand how the managed object stuff is implemented … but doesn’t it kind of have to be iterating over all the managed objects after each iteration of the game loop to see if anything needs to be reallocated? So including less items in the pool should be faster, right?
Because it’s hard to totally avoid cocos2dx memory manage, I think it’s clear to just use it. cocos2dx uses reference count to keep the variable life to the next frame. It cleanup the refCount==0 variables at each frame.
I post my handmade cc::unique_ptr below, which overloads operator T**function to better cope with cocos2dx.
<pre>
namespace cc {
// unique_ptr
template
class unique_ptr {
public:
unique_ptr : ptr {
}
unique_ptr :ptr {
retain;
}
unique_ptr : unique_ptr {
}
~unique_ptr {
release;
}
unique_ptr& operator= {
if {
retain;
release; ptr = ptr;
}
return this;
}
unique_ptr& operator= {
return operator=;
}
T operator-> {
returnptr;
}
const T operator~~> const {
return ptr;
}
operator T* const {
returnptr;
}
private:
void retain { if ptr~~>retain(); }
void release(T ptr) { if ptr->release; }
private:
T _ptr;
};
}
Because it’s hard to totally avoid cocos2dx memory manage, I think it’s clear to just use it. cocos2dx uses reference count to keep the variable life to the next frame. It cleanup the refCount==0 variables at each frame.
>
Yes, cocos2dx memory management is intertwined with its logic throughout the framework. However, I think that it isn’t too hard to not use for a game’s primary allocation and de-allocation. Basically, it’s not that hard to avoid using cocos2d-x memory management in situations where the following are true:
(1) I am explicitely allocating something in my own game code.
(2) The thing that I am explicitly allocating inherits from CCNode
(2) is arbitrary. I do this because it would be a pain in the ass to not use cocos2dx memory management everywhere. (1) is just common sense.
But basically I let cocos2d-x handle management of temporary objects that won’t be retained across iterations of game loop and try to manage primary game data, i.e. sprites, myself. I do worry that I am introducing leaks doing it this way, but it seems to work.
This is an awesome post. However I got some compiler errors now that the custom deleter needs to be part of the unique_ptr template declare. It is probably the pre/post C++11 differences. The below is my update to this code: -
template <class T>
void unique_ptr_deleter(T *p)
{
auto ptr = static_cast<Ref *>(p);
if (ptr)
ptr->release();
}
template <class T>
using unique_ptr = std::unique_ptr<T, decltype(*unique_ptr_deleter<T>)>;
template <class T>
unique_ptr<T> make_unique(T *ptr)
{
if (ptr)
ptr->retain();
return unique_ptr<T>(ptr, unique_ptr_deleter);
}