Proposal for v3.0: shared_ptr vs. manual retain release

if we use the manual retain release the C++,does it mean we must also use manual retain release in the js binding?

Hi there,

I was reading some Waltzer’s Weibo posts and finally re-directed to this discussion here. I found Waltzer’s test code on comparing raw pointer and shared_ptr is pretty interesting. I am far from understanding the whole infrastructure of Cocos2D-X, some questions I will ask might sound dumb :slight_smile:

First of all, his test code kinda mis-uses shared_ptr everywhere like addChild(shared_ptr child) which will call copy constructor to generate temp object and the vector<shared_ptr> which is not recommended if I remember correctly. I have seen some replies pointed out we should pass shared_ptr const reference.

Secondly why do we have to use shared_ptr instead of unique_ptr? Do we have to keep ref counting for each object? vector<unique_ptr> is much more light weight than vector<shared_ptr>. If we have to keep ref counting, can we just ref count on the whole vector? I updated Waltzer’s test code a little like replacing the shared_ptr with unique_ptr and got perf result like:

Cocos2d: Avg unique_ptr duration 0.000390 ms
Cocos2d: Avg c*+ ptr duration 0.000290 ms
It is not that bad, right? :slight_smile:
Thanks!
Zhe Wang wrote:

Sergey Shambir, I think the benefit of std::shared_ptr keeps reference counter outside of object, is std::weak_ptr support.
>
Others:
>
h2. retain/release* autorelease pool
>
Using retain/release + autorelease pool will make multi-threading very complicated.
In 2.x, we purge autorelease pool at the end of each frame; while in multi-threads, we don’t know an object when will an object be released: at the end of each frame drawing in render thread? at the end of each schedule call of physics thread? or other threads? So using v2.x retain/release + autorelease is not a good idea.
>
h2. (B) shared_ptr
>
Is using shared_ptr very slow? No, it’s not very slow, it’s SUPER slow.
Take a look at my performance test https://github.com/walzer/cocos2d-x/tree/SmartPointerPerformance. In this test, I use retain/release vs. shared_ptr to implement a basic node tree then update it. Finally I add 10 layers in a scene, and 50 nodes in each layer, so totally I visit 50 * 10 10 1 = 511 nodes in each frame. Then I run it 100 times to get the average time.
>
| Test Device | CPU | iOS version | build | shared_ptr | retain/release | x times slower |
| iPad Mini | 1 GHz dual-core ARM Cortex-A9 | iOS 6.1.3 | release | 13.229430 ms | 5.392210 ms| 2.45 |
| Galaxy Nexus | 1.2 GHz dual-core ARM Cortex-A9 | Android 4.1.2 | debug | 5.724440 ms | 1.210641 ms | 4.72 |
>
As I mentioned before, 5 times slow happens on Android.
Please point out what’s wrong in my code https://github.com/walzer/cocos2d-x/tree/SmartPointerPerformance.
If 2711 times slower on iOS is true, then that’s a big deal
>
On the other hand, please take a look at google v8’s source code https://code.google.com/p/v8/wiki/Source. V8 heavily uses C*+ templates, but in most codes they use C*+ pointer and new/delete C*+ objects manually, only use Handle to wrap c*+ objects in a few parts. So I think in a performance-eager project, we should avoid using shared_ptr. “FAST” is a selling point of cocos2d for a long long history.
>
h2. © retain/release manually
>
That’s the way I proposed.

Thanks for your feedback.

`Melo Yao:

Backward compatible is something that we care about, and that’s why we are putting a lot of effort in tagging the old API as deprecated. It is functional, but the compiler will raise a warning.
But if we migrate to smart\_ptr@ we won’t be able to be backward compatible, at least with that API. That being said, it could be mitigated by using theautoC**11 feature. eg: \<pre\><code class="cpp"> // Old API CCSprite **sprite = CCSprite::create; // v3.0-pre-alpha0 API Sprite**sprite = Sprite::create // Proposed API for v3.0-alpha0 std::shared\_ptr<Sprite> sprite = Sprite::create; // But by using auto, it will work both with the old API, v3.0-pre-alpha0, and the new proposed API auto sprite = Sprite::create; </code>\</pre\> Besides backward compatibility, and possible performance improvements, I do not see any benefit on using manual/retain release. I think it is error prone, C** unfriendly, and autorelease pools uses more memory thanshared_ptr`.

`WINGC China:
Thanks, interesting stuff.

I think that Sprite::createXXX@ should return anstd::shared_ptrinstead of astd::unique_ptr, and the the cocos2d-x public API should use “values” ofstd::shared_ptr, and notconst references. But internally, the cocos2d-x API could useconst referencesto pass theshared_ptr. I could be wrong, but I think that is the “normal” usage. Anyway, I will do more tests during these weeks to see if the can improve the performance onshared_ptr`.
Thanks!

Thanks for your quick response!

For coding style I personally like pure C*+ so I vote for

auto sprite = Sprite::create;
no need to mention its backward compatibility.
For choosing between shared_ptr or unique_ptr, you are the expert to make the call. From my understanding by now each Sprite instance has to have ref counting in “normal” usage. As you mentioned there are public API of Cocos2d-X that requires value of std::shared_ptr instead reference, and the shared_ptr has performance burden because of ref counting, how about a solution like this:

  1. all internal APIs use and pass raw pointers or wrapped by unique_ptr, no ref counting. their creators have ownership exclusively and manage life-cycle internally.
  2. whenever an instance needs to share with or hand over ownership to Cocos2d-X’s client code via public APIs, the resource are promoted to be managed by shared_ptr to leverage ref counting.
    No performance burden internally and leveraging ref counting to have auto-resource management externally. Does it sound way too optimistic? :stuck_out_tongue:
    Ricardo Quesada wrote:

Thanks for your feedback.
>
`Melo Yao:

Backward compatible is something that we care about, and that’s why we are putting a lot of effort in tagging the old API as deprecated. It is functional, but the compiler will raise a warning.
But if we migrate to smart\_ptr@ we won’t be able to be backward compatible, at least with that API. That being said, it could be mitigated by using theautoC**11 feature. eg: \> \> Besides backward compatibility, and possible performance improvements, I do not see any benefit on using manual/retain release. I think it is error prone, C*+ unfriendly, and autorelease pools uses more memory thanshared_ptr. \> \>WINGC China:
Thanks, interesting stuff.

I think that Sprite::createXXX@ should return anstd::shared_ptrinstead of astd::unique_ptr, and the the cocos2d-x public API should use “values” ofstd::shared_ptr, and notconst references. But internally, the cocos2d-x API could useconst referencesto pass theshared_ptr. I could be wrong, but I think that is the “normal” usage. Anyway, I will do more tests during these weeks to see if the can improve the performance onshared_ptr`.
Thanks!

Ricardo Quesada wrote:

Thanks for your feedback.
>
`Melo Yao:

Backward compatible is something that we care about, and that’s why we are putting a lot of effort in tagging the old API as deprecated. It is functional, but the compiler will raise a warning.
But if we migrate to smart\_ptr@ we won’t be able to be backward compatible, at least with that API. That being said, it could be mitigated by using theautoC**11 feature. eg: \> \> Besides backward compatibility, and possible performance improvements, I do not see any benefit on using manual/retain release. I think it is error prone, C** unfriendly, and autorelease pools uses more memory thanshared_ptr. \> \>WINGC China:
Thanks, interesting stuff.

I think that Sprite::createXXX@ should return anstd::shared_ptrinstead of astd::unique_ptr, and the the cocos2d-x public API should use “values” ofstd::shared_ptr, and notconst references. But internally, the cocos2d-x API could useconst referencesto pass theshared_ptr. I could be wrong, but I think that is the “normal” usage. Anyway, I will do more tests during these weeks to see if the can improve the performance onshared_ptr`.
Thanks!

@Ricardo , Yes, I think smart ptr is better for future, not only the features from C*+ 11 right now , even can sharing the latest improvements apply to smart ptr once bring in further C*+ revisions.
It may be a little bit pain when developer to migrate to 3.0. But it seems most of time, the changes to existing code are merely literal , I think people will take it.

WiNGC China wrote:

For choosing between shared_ptr or unique_ptr, you are the expert to make the call.

Actually the “official” recommendation is to always return a unique_ptr, and it is cheap to convert it into a shared_ptr if needed.
I was thinking that perhaps the the shared_ptr was needed for the creation of the nodes
. but perhaps I’m wrong. I need to do many experiments before deciding the correct API.

  1. all internal APIs use and pass raw pointers or wrapped by unique_ptr, no ref counting. their creators have ownership exclusively and manage life-cycle internally.
  2. whenever an instance needs to share with or hand over ownership to Cocos2d-X’s client code via public APIs, the resource are promoted to be managed by shared_ptr to leverage ref counting.

It sounds good, but I see some cases where it might fail. For example, if addChild() should save in an std::vector<> using unique_ptr, then when you try to get that sprite, what should it return ? a shared_ptr ? or a unique_ptr ? It should return a shared_ptr
 but in order to work correctly I think the std::vector<> should also have shared_ptr


Perhaps I’m wrong
 as I said, before deciding the API, we need to do many tests and experiments.

Taken from gamedev.net:

Smart pointers are a useful feature, but they aren’t a solution to every problem. If every single one of your pointers is a smart pointer, you are definitly doing it wrong. You should only use shared (i.e. reference counted) pointers when you want two different objects to both be the “owner” of a pointer (i.e. shared ownership). This gives either object the ability to free the pointer, but only when both objects no longer reference it. In general though, you should try to create pointers that are owned by only one object, and deleted by only one object. This is a much better way to make sure memory is not leaked.
>
Also, just because you use smart pointers, it doesn’t mean that you will never have a memory “leak”. For instance, if you have two smart pointers, that both retain a reference to each other unless one of them frees the reference to the other, neither pointer will ever be released. So even with smart pointers, you still need to aware of what’s going on.

Why not to leave API with raw pointers and let the user to decide to wrap the API return with a smart_ptr?

std::shared_ptr sprite = std::make_shared(CCSprite::create(...));

Richardo, correct me if I mis-understand anything here. I only have limited experiences with smart pointers and stl containers, and a little more on COM/ATL stuff. I don’t have any experience on Cocos2d-X. I was attracted to this topic from some discussions on Waltzer’s Weibo posts :).

If there is an “official” recommendation for returning unique_ptr, I believe it should only work when the callee needs not to hold the ownership. In the case of Waltzer code the scene orlayers are actually containers and I do not see any chance they give out ownership from code. The sprite instances’ lifecycle is with the containers so vector<unique_ptr<
>> is good enough.

For this specific question

It sounds good, but I see some cases where it might fail. For example, if addChild() should save in an std::vector<> using unique_ptr, then when you try to get that sprite, what should it return ? a shared_ptr ? or a unique_ptr ? It should return a shared_ptr
 but in order to work correctly I think the std::vector<> should also have shared_ptr


If the the public APIs are actually from a container instance and share ownership with callers, return a shared_ptr. If the public APIs are just a factory of sprite instance who gives out ownership to callers, return an unique_ptr. A benefit from C++ 11 is that no matter what the public APIs return the callers just need to leverage auto to let compiler handle what exact type is.

WiNGC China wrote:

Thanks for your quick response!
>
For coding style I personally like pure C++ so I vote for
> auto sprite = Sprite::create(
);
no need to mention its backward compatibility.
>
For choosing between shared_ptr or unique_ptr, you are the expert to make the call. From my understanding by now each Sprite instance has to have ref counting in “normal” usage. As you mentioned there are public API of Cocos2d-X that requires value of std::shared_ptr instead reference, and the shared_ptr has performance burden because of ref counting, how about a solution like this:

  1. all internal APIs use and pass raw pointers or wrapped by unique_ptr, no ref counting. their creators have ownership exclusively and manage life-cycle internally.
  2. whenever an instance needs to share with or hand over ownership to Cocos2d-X’s client code via public APIs, the resource are promoted to be managed by shared_ptr to leverage ref counting.
    >
    No performance burden internally and leveraging ref counting to have auto-resource management externally. Does it sound way too optimistic? :stuck_out_tongue:

That would be the ideal!

WiNGC China wrote:

If there is an “official” recommendation for returning unique_ptr, I believe it should only work when the callee needs not to hold the ownership. In the case of Waltzer code the scene orlayers are actually containers and I do not see any chance they give out ownership from code. The sprite instances’ lifecycle is with the containers so vector<unique_ptr<
>> is good enough.

These 3 articles are excellent references for this topic:

What kind of smart_ptr should we pass ?

shared_ptr vs unique_ptr:

What factories should return (eg: Sprite::createXXX() )

There are 2 things to discuss here:
a) Performance: can we have an acceptable performance by using smart pointers ?
b) What API to use should we migrate to smart pointers

For a), we need to do more performance tests (I’m working on this)
For b)
 well, we need to discuss which is the best API for it (I will work on this once I finished a) )

I started with the tests.
And dispatching methods on shared_ptr is slower than dispatching methods on raw pointers as expected. But to my surprise, it was only slightly slower. I think it is around ~6 percent slower, which is not that much.
On some tests it had the same speed (perhaps the CPU was caching or using registers), on other tests it was about 15 slower
 But the average was about 6.

But I have to continue doing more tests.

With Justin Graham we have been thinking of this for a while, and finally we came out with this solution. But let’s review all the alternatives again first:

a) Manual retain, release, autorelease

This is what is being used in cocos2d-x v2.1.
Basically all objects inherit from Object (it should be called Reference), and it has 3 methods:

void retain(); // increases the refCount
void release(); // decreases the refCount
void autorelease(); // add the object into the autorelease pool

int refCount = 0;

And when refCount is 0, the object gets destroyed. It a simple model, easy to understand
 with the exception of autorelease.
autorelease is a concept imported from Objective-C. It is a pool of objects that gets “flushed” once per frame. So all the objects that are flushed will receive the release method.
Basically it is a way to simulate the smart_ptr behavior in a weird way.
So we discarded this option because we didn’t like the autorelease concept in C*+ and it was not compatible with STL containers.
Example:
<pre>
Object* createObject {
auto object = new Object;
object~~>autorelease;
return object;
}
void start {
// “object” is an “autoreleased” object.
auto object = createObject;
// so “object” will live until the next frame .
// there is not need to manually call “release”
}
</pre>

h3. Pros
~~ It is fast

  • It is backward compatible
    h3. Cons
  • Not C*+ friendly. Many C*+ users ask “What is an autorelease pool ?” And they are right.
  • Not easy to use with STL containers .
  • autorelease pools keep objects alive longer than needed, that means that it allocates memory longer than needed.

h2. b) Manual retain, release, WITHOUT autorelease
This approach is the same as the previous one but without the autorelease pool.
The problem is that users coming from v2.1 would LEAK A LOT OF MEMORY .
So we discarded this alternative.
Example:
<pre>
Object* createObject {
return new Object;
}
void start {
// “object” is just a raw object.
auto object = createObject;
// use the object, or add it into a container.


// manually release it, otherwise memory will be leaked.
object~~>release;
}
</pre>

h3. Pros
~~ It is fast

  • It doesn’t use autorelease pools
    h3. Cons
  • Not so C*+ friendly. Seems like a pure “C” API.
  • API is not backward compatible (object~~>release is needed)
    ~~ Not easy to use with STL containers (a custom smart pointers needs to be used).
  • Super error prone to leak memory

c) Migrate the whole API to Smart Pointers

All the Cons of manual retain/release/autorelease are fixed by using smart pointers.
We evaluated using std::unique_ptr, std::shared_ptr and a custom smart pointer.
In the end we thought that if we were going to migrate everything to smart pointers, std::shared_ptr was a very good solution.
But performance was a big concern
 and rewriting the whole cocos2d was another big concern so we discarded this option.

Pros

  • Smart Pointers are C*+ friendly. In fact they are part of C**11, and have been used by boost users for many many years
  • Easy to use them with STL containers
  • Temporary objects are released from memory as soon as they go out of scope
    h3. Cons
  • Slower than raw pointers . If fact, if the user is not careful, it could generate much slower code.
  • Not backward compatible. Requires a huge rewrite of cocos2d.

h2. d) Hybrid approach: Use SmartPtr and manual retain/release
The hybrid approach gets the benefits of both worlds, with little penalties.
Basically all the factory methods return a custom smart pointer that knows how to deal with retain/release objects , while the rest of cocos2d API remains the same, using raw pointers.

The trick, is that the Smart Pointers are implicitly converted into raw pointers by the compiler, but since the reference counting is being managed by Object both approaches can be used at the same time.
Example:
<pre>
// addChild: same API as v2.1 using raw pointers
void addChild
// factory methods returns SmartPtr<> objects instead of raw pointers.
SmartPtr<Object> createObject {
return SmartPtr<Object>;
}
void doSomething {
// returns a SmartPtr<Object>
auto obj = createObject;
// the SmartPtr<> is implicitly converted to Object* by the compiler
layer~~>addChild;
}
</pre>
h3. Pros
~~ As fast as v2.1

  • autorelease pools are removed
  • C*+ friendly and compatible with STL containers

Cons

Did we miss anything ?
If so, let us know, otherwise we are going to implment the Hybrid approach for v3.0.

UPDATE: Edited some syntax and grammar errors.

Ricardo Quesada wrote:

With Justin Graham we have been thinking of this for a while, and finally we came out with this solution. But let’s review all the alternatives again first:
>
h2. Manual retain, release, autorelease
>
This is what is being used in cocos2d-x v2.1.
Basically all objects inherit from Object (it should be called Reference), and it has 3 methods:
[
]
>
And when refCount is 0, the object gets destroyed. It a simple model, easy to understand
 with the exception of autorelease.
autorelease is a concept imported from Objective-C. It is a pool of objects that gets “flushed” once per frame. So all the objects that are flushed will receive the release method.
Basically it is a way to simulate the smart_ptr behavior in a weird way.
So we discarded this option because we didn’t like the autorelease concept in C*+ and it was not compatible with STL containers.
>
Example:
>
>
>
h3. Pros
>

  • It is fast
  • It is backward compatible
    >
    h3. Cons
    >
  • Not C*+ friendly. Many C*+ users ask “What is an autorelease pool ?” And they are right.
  • Not easy to use with STL containers .
  • autorelease pools keep objects alive longer than needed, that means that it allocates memory longer than needed.
    >
    >
    h2. Manual retain, release, WITHOUT autorelease
    >
    This approach is the same as the previous one but without the autorelease pool.
    The problem is that users coming from v2.1 would LEAK A LOT OF MEMORY .
    So we discarded this alternative.
    >
    Example:
    >
    >
    >
    h3. Pros
    >
  • It is fast
  • It doesn’t use autorelease pools
    >
    h3. Cons
    >
  • Not so C*+ friendly. Seems like a pure “C” API.
  • API is not backward compatible (object~~>release is needed)
    >~~ Not easy to use with STL containers (a custom smart pointers needs to be used).
  • Super error prone to leak memory
    >
    h2. Migrate the whole API to Smart Pointers
    >
    All the Cons of manual retain/release/autorelease are fixed by using smart pointers.
    We evaluated using std::unique_ptr, std::shared_ptr and a custom smart pointer.
    In the end we thought that if we were going to migrate everything to smart pointers, std::shared_ptr was a very good solution.
    But performance was a big concern
 and rewriting the whole cocos2d was another big concern so we discarded this option.
    >
    h3. Pros
    >
  • Smart Pointers are C*+ friendly. In fact they are part of C**11, and have been used by boost users for many many years
  • Easy to use them with STL containers
  • Temporary objects are released from memory as soon as they go out of scope
    >
    h3. Cons
    >
  • Slower than raw pointers . If fact, if the user is not careful, it could generate much slower code.
  • Not backward compatible. Requires a huge rewrite of cocos2d.
    >
    >
    h2. Hybrid approach: Use SmartPtr and manual retain/release
    >
    The hybrid approach gets the benefits of both worlds, with little penalties.
    Basically all the factory methods return a custom smart pointer that knows how to deal with retain/release objects , while the rest of cocos2d API remains the same, using raw pointers.
    >
    >
    The trick, is that the Smart Pointers are implicitly converted into raw pointers by the compiler, but since the reference counting is being managed by Object both approaches can be used at the same time.
    >
    Example:
    >
    >
    h3. Pros
    >
  • As fast as v2.1
  • autorelease pools are removed
  • C*+ friendly and compatible with STL containers
    >
    h3. Cons
    >
  • Converting SmartPtr<> to * implicitly could bring some errors:
  • http://herbsutter.com/2012/06/21/reader-qa-why-dont-modern-smart-pointers-implicitly-convert-to/
  • http://www.informit.com/articles/article.aspx?p=31529&seqNum=7
  • Factory methods should be converted to return SmartPtr<> objects (although not as expensive as migrating the whole API)
    >
    >
    Did we miss anything ?
    If so, let us know, otherwise we are going to implment the Hybrid approach for v3.0.
    >
    UPDATE: Edited some syntax and grammar errors.
    It’s really so smart a way to replacing the auto release.

The Hybrid approach sounds really awesome, truly the best of two worlds.

I just wanted to throw in my 2 cents, and suggest a migration tool for projects using older coco2d versions? I mean, I understand that backward compatibility is very important and all that, but if there is a convenient migration tool that helps the users migrate to the newer API, they just might be willing to take the bullet for upgrading to the new API.

I like the first approach.
“Manual retain, release, autorelease”

I like this approach, I’m very experienced with C**, my first contact with C** became when I begin to develop games using cocos2d-x.

Use C++11 is not important for me.

This approach is fast and backward compatibly.

For me is the “Manual retain, release, autorelease” is the best choice.

The hybrid approach is, by far, the best, as you won’t be able to delete a owned object without yourself being the owner or calling delete explicitly.
It’s also quite thread safe, as the only the owner carries reference counting and it’s it’s job to ensure it.

Fabio Cunha wrote:

I like the first approach.
“Manual retain, release, autorelease”
>
I like this approach, I’m very experienced with C**, my first contact with C** became when I begin to develop games using cocos2d-x.
>
Use C11 is not important for me.
>
This approach is fast and backward compatibly.
>
For me is the “Manual retain, release, autorelease” is the best choice.
You should look into C
11, feels like a whole new language with the multi-threading api!
It’s also a huge time saver.

Cocos2d-x needs to use modern C**, and that means it’s going to use new standard features as long as they are supported on their platforms.
You cannot stop progress! :smiley:

Mazyod Jal wrote:

The Hybrid approach sounds really awesome, truly the best of two worlds.
>
I just wanted to throw in my 2 cents, and suggest a migration tool for projects using older coco2d versions? I mean, I understand that backward compatibility is very important and all that, but if there is a convenient migration tool that helps the users migrate to the newer API, they just might be willing to take the bullet for upgrading to the new API.
C** syntax is hell. You’re asking a lot there


I believe it’s a very good decision.
Keep going!

The trick, is that the Smart Pointers are implicitly converted into raw pointers by the compiler, but since the reference counting is being managed by Object (and not by the smart pointer object) both approaches can be used at the same time.

My 2 cents: the main utility of smart pointers is to encapsulate reference counting and memory management. If the Object still has retain()/release() methods, then smart pointers doesn’t seem to have much of a use, and the Hybrid method will seem really awkward to newcomers.

void doSomething() {
   // returns a SmartPtr
   auto obj = createObject();

   // the SmartPtr<> is implicitly converted to Object* by the compiler
   layer->addChild( obj );
}

What’s really happening in that code? Smart pointers copy ctor retains Object, passes it to addChild() method which explicitly retains it one more time when adding to child array, after that we’re at the end of the block, so smart pointer’s dtor calls release() on Object. But what’s the role of smart pointer here? What happens if we remove it? Object is allocated by new, then it’s reference count is raised when it’s added as child, then, after some time, the object is removed and released, reference count equals zero and the object is deleted. Everything seems ok.

Concerning STL compatibility it comes to a funny thing: if smart pointers are used with STL containers like vectors for instance, cocos Objects are retained and released automatically. But internally when adding objects to CCArray we still will have to retain and release them manually even if CCArrays will be replaced by STL vectors, because we are passing raw pointers to addChild(). By the way, STL containers can be used OK right now, you just have to be sure that corresponding objects exist in memory which is not a big deal.

One more issue - auto. From my point of view, extensive use of that feature will make code much less readable. It’s intended to be used for interator declarations, but for SmartPtr

I think it’s better to use typedef like it’s done with string in STL.

The Hybrid method as I understood it, wouldn’t require significant changes in Cocos API, but it doesn’t seem too useful as well. No pain - no gain.

At some point I stopped to understand why we even need autorelease mechanism. It will save us if we create cocos Object with new and forget to delete it, or if an exception will arise before delete statement. But I haven’t seen a lot of exception code in Cocos and normally there’s no need to call delete. Calling retain() and then release() will properly delete the object, if I’m not mistaken, and that’s what happens when we add a Sprite to the BatchNode and then remove it.

Please correct me if I’m wront at some point.

Thanks for the feedback!

Victor Komarov wrote:

My 2 cents: the main utility of smart pointers is to encapsulate reference counting and memory management. If the Object still has retain()/release() methods, then smart pointers doesn’t seem to have much of a use, and the Hybrid method will seem really awkward to newcomers.

Actually the smart pointers solve the autorelease issue, which is not a minor issue, and solves compatibility with STL containers.

Concerning STL compatibility it comes to a funny thing: if smart pointers are used with STL containers like vectors for instance, cocos Objects are retained and released automatically. But internally when adding objects to CCArray we still will have to retain and release them manually even if CCArrays will be replaced by STL vectors, because we are passing raw pointers to addChild(). By the way, STL containers can be used OK right now, you just have to be sure that corresponding objects exist in memory which is not a big deal.

If you use STL containers with raw pointers, you run the risk of using invalid pointers, and that is a big deal. Fixing those kind of bugs are not easy to find. And we want to solve that issue in the library.
One of the goals of cocos2d is to solve all the low level stuff for its users: Users should not think about memory management. Our users should think of creating great games, not in low level stuff.

One more issue - auto. From my point of view, extensive use of that feature will make code much less readable. It’s intended to be used for interator declarations, but for SmartPtr

I think it’s better to use typedef like it’s done with string in STL.

You are free to use auto as you please, but the current recommendation is to use to local variables as well.

The Hybrid method as I understood it, wouldn’t require significant changes in Cocos API, but it doesn’t seem too useful as well.

Actually I find it very useful for all the points that I mentioned earlier, but its OK to disagree.

No pain - no gain.

mmm?
This is not about rewriting everything for the sake of rewriting it.
Please read why I discarded a full smart_ptr API: Not only it will break compatibility in a big way (we care about our users, and we don’t want them to rewrite its addons/extensions/games if it could be avoided), but also it is slower
 potentially much slower if the change is not done correctly.

At some point I stopped to understand why we even need autorelease mechanism. It will save us if we create cocos Object with new and forget to delete it, or if an exception will arise before delete statement. But I haven’t seen a lot of exception code in Cocos and normally there’s no need to call delete. Calling retain() and then release() will properly delete the object, if I’m not mistaken, and that’s what happens when we add a Sprite to the BatchNode and then remove it.

Please, see example C) from this post: http://www.cocos2d-x.org/boards/6/topics/30253

I don’t want an API like C) in cocos2d: super error prone, super verbose, and no benefits.

Thanks for the feedback.

Fabio Cunha wrote:

I like the first approach.
“Manual retain, release, autorelease”
>
I like this approach, I’m very experienced with C**, my first contact with C** became when I begin to develop games using cocos2d-x.

So autorelease not only is a foreign concept in C*+ , but a major issue:

  • memory: All temporary objects will be held in memory until the autorelease pool is flushed.
    That means that you will be using unnecessary RAM in your game and that could be a real issue. On mobile devices like iOS, if you exceed the RAM limit, your game will be killed. Just like that. So cocos2d-x should free the memory that is no longer used as soon as possible.

Use C11 is not important for me.
I think C
11 will allow us to develop games is faster way, and that is good thing.
I think one big drawback of C*+ is that you need to type too many “characters” in order to achieve something, and C++11 tries to solve some of those issues with auto variables, new iterators, lambda objects, and other built-in extensions like threading and smart pointers.

This approach is fast and backward compatibly.

agreed.

For me is the “Manual retain, release, autorelease” is the best choice.

disagreed :slight_smile: