Defining and Using Smart Pointers

Base Classes

You can declare smart pointers to any of the classes that publicly derive from IlsRefCounted. This class manages reference counting.

The class IlsRefCounted is the base class for IlsEntity and IlsObject, which are in turn base classes for all Server object types.

Thus, you can declare smart pointers to any Server object types.

Base Classes for Server Objects

Classes IlsEntity, IlsObject, and IlsRefCounted are fully documented in the Server Reference Manual.

Defining Smart Pointers

To define smart pointers to an arbitrary class A, you can instantiate the class template , as follows:

typedef IlsSmartPointer<A> AP;

AP designates the class “smart pointers to A”. The name AP is an alias for an instance of the IlsSmartPointer template to class A. Once a smart pointer to a class has been defined, you can use its alias each time you need to manipulate a smart pointer to this class.

Note

 The notation we use to name a smart pointer to a class of objects, that is, a P appended to the name of the class, is a user-defined notation, and as such is not
compulsory; you can name a smart pointer the way you want. Note, however, that the notation we have chosen is very close to the notation used for an ordinary pointer, that is A*, in which we have just replaced the asterisk with a P.

Class A does not need to be visible when the smart pointer is declared; a forward declaration is necessary and sufficient. Actually, A can be either a class or a struct.

class A;

typedef IlsSmartPointer<A> AP;

class A:

public IlsObject

{

};

Using Smart Pointers

With smart pointers, destructors are set off at logical moments, corresponding to a natural extension of conventional C++ rules. C++ destroys an object under two conditions:

  • Whenever the object is no longer visible within its scope (for example, at the end of its declaration block).

  • Whenever the object is no longer visible from its process (for example when the main function returns).

Similarly, smart pointers trigger the deletion of an object allocated by new as soon as this object is no longer visible from the stack or from any smart pointer (stored in variables or declared as an object data member).

Consider class Screen and its associated smart pointer ScreenP:

{

  ScreenP ss=new Screen();

  ..

}

// The screen gets deleted

When the block is left, if the object created is visible only to ss, then the object destructor is called.

When you use a smart pointer to an object, you must not explicitly delete the object. If you do so, you might violate data integrity.

Warning

 We strongly advise you against the practice of defining both smart and ordinary pointers to the same Server object. The behavior of smart pointers is guaranteed only if you exclusively use smart pointers to a given Server object.

You must not create smart pointers to objects that have not been allocated by new —for example, objects on the stack, global objects, objects nested in other objects. Also, you must not create smart pointers to objects whose destructor is already in the call stack. Doing so, you would, among other things, destroy the same object twice.

Dereferencing a null smart pointer throws the IlsNullPointerDereferencing exception. For details about exceptions, see Exception Handling.

Some compilers do not implement separate compilation of templates. Thus, it is sometimes necessary to put the definition of a class A in compilation units containing the smart pointer definition.

Warning

 It is not possible to pass a smart pointer to A to a function that expects a smart pointer to B, base class of A. In practice, to carry out such a conversion, the compiler would first have to convert the smart pointer to A to an ordinary pointer to A (a user-defined conversion) and then to carry out an implicit conversion from A* to B*. Then, it would have to build a smart pointer to B, starting from B*, and that, too, counts as a supplementary user-defined conversion. C++ can implicitly carry out one user-defined conversion at most. In such a case, to “help out’’ the compiler, you must use the member function getValue of the smart pointer to eliminate that first user-defined conversion. For details about this function, see the Server Reference Manual. Also, for some compilers, converting the constant 0 to a smart pointer requires two user-defined conversions: the first one to convert 0 to a pointer type, the second one to convert the pointer to the smart pointer. In this case, you have to “help” the compiler by casting the constant 0 to the pointer type. If tp is a smart pointer to T, you have to write tp=(T*)0; to be able to compile.