Kernel SDK Developer's Guide > Basic Operations > Working with Smart Pointers > Functionality of Smart Pointers
Functionality of Smart Pointers

The OdSmartPtr template class and OdRxObjectPtr class provide the common functionality for working with smart pointers. You can initialize them in any manner:

MyObjPtr pSmart = OdRxObjectImpl<MyObj>::createObject();
OdRxObjectPtr pSmartRx = OdRxObjectImpl<MyObj>::createObject();

To take a method or a property of the object to which the smart pointer refers, use the (–>) operator, as when you use a raw pointer:

pSmart -> MyMethod();
pSmartRx -> MyProperty;

To get the raw pointer from the smart pointer, use the get method:

MyObj* pMy = pSmart.get();
OdRxObject* pObjRx = pSmartRx.get();

To set the smart pointer to the raw pointer or another smart pointer, use the assignment operator or constructor. For example:

MyObjPtr pSmart1 = pMy;
MyObjPtr pSmart2 = pSmart;
MyObjPtr pSmart3(pMy, kOdRxObjAttach);

OdRxObjectPtr pSmartRx1 = pObjRx;
OdRxObjectPtr pSmartRx2 = pSmartRx;
OdRxObjectPtr pSmartRx3(pObjRx, kOdRxObjAttach);

If the smart pointer stores NULL, the assignment operator assigns the address of the smart pointer and increments the reference counter of the specified instance. If the smart pointer already stores the address of another instance, the assignment operator decrements its reference counter, assigns the address of the specified instance for the smart pointer, and increments the reference counter of the specified instance. When the assignment operator decrements the reference counter of the current instance, it checks whether the counter is zero, and destroys the instance when its reference counter becomes zero. When you use the constructor, you can pass the kOdRxObjAttach option, which suppresses incrementing of the reference counter.

The assignment operator checks the class type. If the smart pointer is typified, that is, it was created by the OdSmartPtr class, and you try to assign the address of an instance having another type, the assignment operator generates the exception. If the smart pointer is non-typified, that is, it was created by the OdRxObjectPtr class, you can assign the address of any object derived from the OdRxObject class and an exception is not generated.

To compare two smart pointers, use the comparison operators (==), (!=) that check whether the smart pointers store the same address. For example:

OdRxObjectImpl<MyObj> my1;
OdRxObjectImpl<MyObj> my2;

MyObjPtr pSmart1 = &my1;
MyObjPtr pSmart2 = &my2;
MyObjPtr pSmart3 = &my1;

odPrintConsoleString(L"\n(p1==p2)?%d", (pSmart1 == pSmart2));   // 0 (false)
odPrintConsoleString(L"\n(p1==p3)?%d", (pSmart1 == pSmart3));   // 1 (true)
odPrintConsoleString(L"\n(p2!=p3)?%d", (pSmart2 != pSmart3));   // 1 (true)

To verify whether the smart pointer is NULL, use the isNull() method, which returns a true value when the smart pointer is NULL or returns a false value when the smart pointer stores the address of an instance. If the smart pointer was not initialized when it was created, it is set to NULL by default. For example:

OdRxObjectImpl<MyObj> my3;

MyObjPtr pSmart1 = &my3;
MyObjPtr pSmart2;

odPrintConsoleString(L"\n(p1==Null)?%d", pSmart1.isNull());     // 0 (false)
odPrintConsoleString(L"\n(p2==Null)?%d", pSmart2.isNull());     // 1 (true)

To assign the address of an instance without incrementing the reference counter, use the attach() method. The attach() method assigns the address of the specified instance for the smart pointer, but it does not increment the reference counter of the specified instance. The attach() method requires the pointer. For example:

OdRxObjectImpl<MyObj> my;
odPrintConsoleString(L"\nRefs=%d", my.numRefs());               // 1

MyObjPtr pSmart;                                                // = null

pSmart.attach(&my);                                             // = my
odPrintConsoleString(L"\nRefs=%d", my.numRefs());               // 1

If the smart pointer already stores the address of another instance, the attach() method decrements the reference counter of the other instance, assigns the address of the specified instance, and does not increment the reference counter of the specified instance. Continuing the example:

OdRxObjectImpl<MyObj> myX;

MyObjPtr pSmartX = &myX;                                        // = myX
odPrintConsoleString(L"\nRefs=%d", myX.numRefs());              // 2

pSmartX.attach(&my);                                            // = my

odPrintConsoleString(L"\nRefs=%d", myX.numRefs());              // 1
odPrintConsoleString(L"\nRefs=%d", my.numRefs());               // 1

To clear the smart pointer without decrementing the reference counter, use the detach() method. The detach() method returns the address of the current instance, sets a NULL for the smart pointer, and does not decrement the reference counter of the current instance. You can use the returned value as the raw pointer to the detached instance. Continue the example:

MyObj* pObj;
pObj = pSmart.detach();                                         // pSmart = null // pObj = my
odPrintConsoleString(L"\nRefs=%d", my.numRefs());               // 1

To clear the smart pointer, use the release() method. The release() method sets a NULL for the smart pointer, decrements the reference counter of the current instance, and destroys the instance when the reference counter becomes zero. Continuing the example:

MyObjPtr pSmart1 = OdRxObjectImpl<MyObj>::createObject();

MyObj* pMy = pSmart1.get();
odPrintConsoleString(L"\nRefs=%d", pMy->numRefs());             // 1

MyObjPtr pSmart2 = pSmart1;
odPrintConsoleString(L"\nRefs=%d", pMy->numRefs());             // 2

pSmart1.release();
odPrintConsoleString(L"\nRefs=%d", pMy->numRefs());             // 1

pSmart2.release();                                              // 0 - object is destroyed

The OdRxObjectPtr class is similar to the OdSmartPtr class, but it allows you to operate using smart pointers of any classes derived from the OdRxObject. You do not need to define the smart pointer type for it. The OdRxObjectPtr class is a non-typified smart pointer. The attach() method requires the raw pointer of the OdRxObject type. The detach() method returns the raw pointer of the OdRxObject type. For example:

OdRxObjectPtr pSmartRx0 = OdRxObjectImpl<MyObj>::createObject();

OdRxObject* pObjRx = pSmartRx0.get();
odPrintConsoleString(L"\nRefs=%d", pObjRx->numRefs());          // 1

OdRxObjectPtr pSmartRx1 = pSmartRx0;                            // = pObjRx
OdRxObjectPtr pSmartRx2 = pSmartRx1;                            // = pObjRx
odPrintConsoleString(L"\nRefs=%d", pObjRx->numRefs());          // 3

OdRxObjectPtr pSmartRx3;                                        // = null

pSmartRx3.attach(pObjRx)                                        // = pObjRx
odPrintConsoleString(L"\nRefs=%d", pObjRx->numRefs());          // 3

OdRxObjectImpl<MyObj> my;

pSmartRx3.attach(&my)                                           // = my
odPrintConsoleString(L"\nRefs=%d", pObjRx->numRefs());          // 2

pSmartRx2.detach()                                              // = null
pSmartRx3.detach()                                              // = null
odPrintConsoleString(L"\nRefs=%d", pObjRx->numRefs());          // 2

pSmartRx1.release();                                            // = null
odPrintConsoleString(L"\nRefs=%d", pObjRx->numRefs());          // 1

pSmartRx0.release();                                            // 0 - object is destroyed

The destructor of the OdSmartPtr class or the OdRxObjectPtr class calls the release() method before deleting the smart pointer. Therefore smart pointers declared as automatic variables, static variables, members of structures, or arguments of functions automatically decrement the reference counters of their own instances when the smart pointer scope is finished.

See Also

Working with Smart Pointers

Implementing Smart Pointers

Example of Assigning Smart Pointers

Copyright © 2002 – 2020. Open Design Alliance. All rights reserved.