5. Working with Smart Pointers
<< RETURN TO THE PREVIOUS SECTION
In UNIGINE, instances of C++ API classes (such as: node, mesh, body, image, etc.) only store pointers to instances of internal C++ classes, they cannot be created and deleted via the standard new/delete operators. So they should be declared as smart pointers (Unigine::Ptr) that allow you to automatically manage their lifetime. UNIGINE has its own optimized memory allocator for faster and more efficient memory management.
To create an instance of an internal class we should declare a smart pointer for the class we are going to instantiate and call the create() method - class constructor - providing construction parameters if necessary.
// instantiating an object of an internal class
<Class>Ptr instance = <Class>::create(<construction_parameters>);
All objects are divided into two groups regarding the way their lifetime is managed:
Ownership Objects#
Ownership objects (Image, Texture, Mesh, Tileset, etc.) — these objects are managed in accordance with reference counter, i.e. how many smart pointers are pointing to the managed object; when the last smart pointer is destroyed, the counter goes to 0. In this case it is assumed that the object is no longer needed (the Engine doesn’t know anything about it, and the user has got no pointer to be able to use it) and, therefore, it is deleted. (e.g. such objects declared within a scope will be automatically deleted when leaving the scope).
// creating a new image
ImagePtr img = Image::create();
// now two pointers point to our image (reference counter increment)
ImagePtr img2 = img;
// removing the image (as both pointers no longer point to it and reference counter is zero)
img2 = img = nullptr;
// another way to clear pointers
img.clear();
img2.clear();
Non-Ownership Objects#
Non-ownership objects (nodes, widgets, materials, properties, etc.) — these objects interact with the Engine and become managed by it since the moment of their creation (they are engaged in the main loop, can be retrieved by names, etc.). The lifetime of these objects is not determined by the reference counter, they provide the mechanism of weak references, so you can check whether an object was deleted or not. To delete such objects you should use deleteLater() or a corresponding manager’s method (e.g.: Materials::removeMaterial()).
NodePtr node;
void somefunc1(){
// creating a new dummy node
node = NodeDummy::create();
}
void somefunc2(){
// checking whether the node exists
if (node)
Log::message("The node is alive\n");
// deleting the node
node.deleteLater();
}
Instead of managing references for nodes manually now you can simply choose lifetime management policy for it:
- World-managed - in this case a node shall be deleted when the world is closed. This policy is used by default for each new node.
- Engine-managed - in this case the node shall be deleted automatically on Engine shutdown (can be used for nodes that should be kept when changing worlds).
NodePtr node = NodeDummy::create();
NodePtr node2 = NodeDummy::create();
// the node shall be deleted on world shutdown
node->setLifetime(Node::LIFETIME_WORLD);
// the node2 shall remain alive even when another world is loaded
node2->setLifetime(Node::LIFETIME_ENGINE);
Additional information:
- For more information on managing smart pointers, see Working with Smart Pointers page.
- For more information on ownership management, see Memory Management page.