Use of the auto
keyword is encouraged for better code readability. Please refer to Herb Sutter's AAA (Almost Always Auto) post.
Please read this thread for the discussion of converting raw pointers to smart pointers in the cocos2d-x code.
Since the engine's code still uses raw pointers, there are two possible strategies:
- Keep using raw pointers to manage the lifetime of your own objects
- Pros: max performance, familiar code
- Cons: needs manual tracking of heap-allocated objects to prevent memory leaks
- Use a hybrid approach - use smart pointers for managing your own objects and use raw pointers when dealing with the game engine
- Pros: easier management of object lifecycles by assigning ownership
- Cons: slower in performance compared to manual memory management (this was the reason for the game engine not adopting smart pointers for the v3.0 update), new and unfamiliar code
Advice: Opt for the hybrid approach unless you are absolutely particular of getting the best performance. The following section talks about the hybrid approach.
Let us assume that you have scene classes in your game which have game objects/widgets as members. A scene is instantiated when the Director pushes it to the front of the render queue. A scene is destroyed when it is replaced by another scene or when the game quits. This makes it easy to say that each scene will "own" the game objects i.e the member game objects live and die with their associated scenes. This is a perfect use case for the std::unique_ptr
.
//raw pointer
_widget = new widget{};
...
//destroy
delete _widget;
//smart pointer
_widget = make_unique<widget>();
Note: make_unique is a C++14 addition. You can use Herb Sutter's version (http://herbsutter.com/gotw/_102/) for C++11:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Note that there's no need to track and delete the smart pointer version - it will be automatically deleted when its owner (the scene in this case) gets deleted.
Quoting Herb Sutter:
- Prefer to allocate objects to be managed by a shared_ptr using make_shared, and objects to be managed by a unique_ptr with make_unique.
- Although Standard C++ does not yet have make_unique, this is mostly an oversight and it will almost certainly eventually be added. In the meantime, use the version shown above, and your code will be forward-compatible with the likely direction of the C++ standard.
- Avoid using plain new or other raw unmanaged allocation directly. Instead, use a factory like make_unique that wraps the raw allocation and immediately passes it to another object that will own the resource. Often that owning object will be a smart pointer, but it can be a scope guard or any other kind of owning object whose destructor will deallocate the resource safely.
####Obtaining raw pointers from smart pointers
When you need to interface with the engine API, you will need to supply raw pointers. For e.g. when you want to register a callback, you can use the get()
method:
//_game is a unique_ptr
contactListener->onContactBegin = CC_CALLBACK_1(GameLayer::onContactBegin, _game.get());
- Herb Sutter's Elements of Modern C++ Style
- Scott Meyer's Effective Modern C++