[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Smart pointers are a new feature in Crystal Space 0.95. The purpose of
smart pointers is to make it easier to manage reference counting.
So instead of manually taking care of calling IncRef
and
DecRef
on your objects you use smart pointers (csRef
) and
let those take care.
This is easy. For example, often you want to keep track of a few common objects in your main class (like the pointer to the engine and so on). To do this you just declare in your main class:
class MyClass { csRef<iEngine> engine; ... } |
Smart pointers don't need to be initialized. So there is no need
to do `engine = 0' in the constructor of your class.
There is also no need to clean them up. The reference to the engine
will be cleaned up automatically when the instance of MyClass
is deleted.
To fill the engine smart pointer with a pointer to the engine you can use the following code (assuming the engine plugin is loaded):
engine = CS_QUERY_REGISTRY (object_reg, iEngine); engine->CreateSector (); ... |
So that's it. I will show you how this would be written before smart pointers existed:
class MyClass { iEngine* engine; ... } MyClass::MyClass () { engine = 0; } MyClass::~MyClass () { if (engine) engine->DecRef (); } ... engine = CS_QUERY_REGISTRY (object_reg, iEngine); engine->CreateSector (); ... ... |
The advantage doesn't seem huge but in general it is a LOT easier
to use smart pointers. Especially when you have multiple exit points
(error handling). The nice thing about smart pointers is that you can
use them exactly like you would use a normal pointer (i.e. you can
do things like engine->CreateSector ()
).
Here is another very common example on how you can use smart pointers:
csRef<iMeshWrapper> sprite(engine->CreateMeshWrapper(...)); csRef<iSprite3DState> state (SCF_QUERY_INTERFACE ( sprite->GetMeshObject (), iSprite3DState)); state->SetAction ("default"); |
csPtr
is a companion class which helps in the transition from
the old (pre-smart pointer) API to the new one. Basically the idea is
that all functions that used to return a pointer that the caller
had to DecRef
will now return a csPtr
. A csPtr
is basically a simple pointer container. It just represents the
pointer itself. csPtr
will not do any IncRef
or DecRef
.
It just stores the pointer. There are two ways to use the result of a
function that returns a csPtr
:
// Declaration of function. struct iEngine { virtual csPtr<iLight> CreateLight (...) = 0; ... } // First way to use this function (old style API): iLight* light = engine->CreateLight (...); // Use 'light' pointer. ... // DecRef() when ready. if (light) light->DecRef (); // Second way to use this function (new style API): csRef<iLight> light (engine->CreateLight (...)); // Use 'light' pointer. ... |
So when a csPtr
is assigned to a csRef
the pointer
will be transfered into the csRef
without an additional
IncRef
(i.e. the csRef
inherits the reference from the
csPtr
). On the other hand when the csPtr
is simply
assigned to the normal pointer then nothing special will happen so
the caller is responsible for calling DecRef
manually.
By using csPtr
we are able to make the API smart pointer aware
without sacrificing API compatibility.
To make it easier for functions to actually return a csPtr
when
they are internally working with a csRef
there is also an
automatic conversion from csRef
to csPtr
. This means
that the following construct is ok:
csPtr<iBla> MyFunction () { csRef<iBla> bla = ...; ... return csPtr<iBla> (bla); } |
Basically what happens above is that the csPtr
constructor
which takes a csRef
will call IncRef
on the pointer.
This is needed because when the csRef
inside MyFunction()
goes out of scope it will call DecRef
potentially destroying
the reference.
However, the following is wrong:
iBla* MyFunction () { csRef<iBla> bla = ...; ... return bla; } |
Because here nothing will call IncRef
on the returned pointer
but the csRef
will still call DecRef
. If you really want to
return a normal pointer (which is probably not a good idea) in this case
then you must first call IncRef
manually before returning.
Another way to use csPtr
is as follows:
csRef<iView> view; view = csPtr<iView> (new csView (...)); |
When making a new object (new csView
) there is automatically
one reference already. So when assigning that to a csRef
you
need to encapsulate the pointer in a csPtr
first so that no
additional IncRef
is called. The following code would have
caused a memory leak because there would be two references to the
view:
csRef<iView> view; view = new csView (...); // Don't do this! |
WARNING Only use csPtr
in the situations described above!
Never use a csPtr
to store something. Never pass
csPtr
instances as parameters to some other function.
In the current Crystal Space API there are now three possible return values for functions (assuming the function returns a pointer):
csRef
in which case the csRef
will increment the
reference count and decrement it again when it is destroyed. You can also assign
this to a normal pointer and not worry about reference counting either
(but you will not own the reference).
csPtr
. In this case you can assign it
to a csRef
which will inherit the reference from the csPtr
(i.e.
the reference count is not incremented). When the csRef
is destroyed
the reference count is decremented. So functions returning csPtr
actually transfer a reference to the caller.
csRef
. In this case you can assign
it to another csRef
which will work correctly with regards
to reference counts. It is also safe to not store the pointer
but directly use it like this: Function()->DoSomething()
. This is
something that is not legal with csPtr
. However it is NOT safe
to assign the result of a function returning csRef
to a normal
pointer as after assignment an immediate DecRef
will happen
(which may cause destruction of the object in some cases). So functions
returning csRef
are not compatible with old style API.
As already noted above, only use csPtr
for returning already
incremented references and for wrapping a new object before storing
it in a csRef
. Do not use it for anything else.
Also, when a function returns a csPtr
you MUST assign the
result to either a csRef
or else a normal pointer (and call
DecRef
) later. If you don't do that then you will have a memory
leak (or reference leak). i.e the following code is illegal because
it ignores the returned mesh wrapper:
engine->CreateMeshWrapper (...); // Don't do this! |
Note that if you are in debug mode then CS will add a runtime test for this bad usage (i.e. your program will crash when you use something like the above).
When using smart pointers (i.e. csRef
) correctly you should
be careful when using IncRef()
and DecRef()
manually.
Avoid constructs like this:
csRef<iMeshWrapper> mesh = ...; ... mesh->DecRef (); mesh = 0; |
As this will cause two references to be decremented! And that is most likely not what you want.
Due to the way the current implementation of
csInitializer::DestroyApplication()
works, you MUST make sure that
all your references to Crystal Space objects are released BEFORE calling
DestroyApplication
. So the following code is not good:
int main (int argc, char* argv[]) { ... csRef<iPluginManager> plugin_mgr (CS_QUERY_REGISTRY (object_reg, iPluginManager)); ... csInitializer::DestroyApplication (object_reg); return 0; } |
The reason this doesn't work is that the `plugin_mgr' reference
will only be cleaned up after DestroyApplication
is called.
To fix this you can use several techniques. Manually setting
`plugin_mgr' to 0 right before calling DestroyApplication
is one way. Another way is to put the initialization into another
routine so that `plugin_mgr' is created in another scope.
For the same reason it is also not good to call DestroyApplication
from within the destructor of your main class. If you do that then
when your main instance is deleted, first DestroyApplication
is
called and only then are the smart pointers released which your
main instances may have.
The include files useful for this section are:
#include "csutil/ref.h" |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |