IceUtil::Handle
implements a smart reference-counted pointer type. Smart pointers are used to guarantee automatic deletion of heap-allocated class instances.
Handle
is a template class with the following interface:
{zcode:cpp} template<typename T> class Handle : /* ... */ { public: typedef T element_type; T* _ptr; T* operator->() const; T& operator*() const; T* get() const; operator bool() const; void swap(HandleBase& other); Handle(T* p = 0); template<typename Y> Handle(const Handle<Y>& r); Handle(const Handle& r); ~Handle(); Handle& operator=(T* p); template<typename Y> Handle& operator=(const Handle<Y>& r); Handle& operator=(const Handle& r); template<class Y> static Handle dynamicCast(const HandleBase<Y>& r); template<class Y> static Handle dynamicCast(Y* p); }; template<typename T, typename U> bool operator==(const Handle<T>& lhs, const Handle<U>& rhs); template<typename T, typename U> bool operator!=(const Handle<T>& lhs, const Handle<U>& rhs); template<typename T, typename U> bool operator<(const Handle<T>& lhs, const Handle<U>& rhs); template<typename T, typename U> bool operator<=(const Handle<T>& lhs, const Handle<U>& rhs); template<typename T, typename U> bool operator>(const Handle<T>& lhs, const Handle<U>& rhs); template<typename T, typename U> bool operator>=(const Handle<T>& lhs, const Handle<U>& rhs); {zcode} |
Note that the actual implementation is split into a base and a derived class. For simplicity, we show the combined interface here. If you want to see the full implementation detail, it can be found in |
The template argument must be a class that derives from Shared
or SimpleShared
(or that implements reference counting with the same interface as these classes).
This is quite a large interface, but all it really does is to faithfully mimic the behavior of ordinary C++ class instance pointers. Rather than discussing each member function in detail, we provide a simple overview here that outlines the most important points. Please see the discussion of Ice objects for more examples of using smart pointers.
element_type
This type definition follows the STL convention of defining the element type with the fixed name element_type
so you can use it for template programming or the definition of generic containers.
_ptr
This data member stores the pointer to the underlying heap-allocated class instance.
These member functions allow you to construct, copy, and assign smart pointers as if they were ordinary pointers. In particular, the constructor and assignment operator are overloaded to work with raw C++ class instance pointers, which results in the "adoption" of the raw pointer by the smart pointer. For example, the following code works correctly and does not cause a memory leak:
{zcode:cpp} typedef Handle<MyClass> MyClassPtr; void foo(const MyClassPtr&); // ... foo(new MyClass); // OK, no leak here. {zcode} |
operator->
, operator*
, and get
The arrow and indirection operators allow you to apply the usual pointer syntax to smart pointers to use the target of a smart pointer. The get
member function returns the class instance pointer to the underlying reference-counted class instance; the return value is the value of _ptr
.
dynamicCast
This member function works exactly like a C++ dynamic_cast
: it tests whether the argument supports the specified type and, if so, returns a non-null pointer; if the target does not support the specified type, it returns null.
The reason for not using an actual |
For example:
{zcode:cpp} MyClassPtr p = ...; MyOtherClassPtr o = ...; o = MyOtherClassPtr::dynamicCast(p); if (o) { // o points at an instance of type MyOtherClass. } else { // p points at something that is // not compatible with MyOtherClass. } {zcode} |
Note that this example also illustrates the use of operator bool
: when used in a boolean context, a smart pointer returns true if it is non-null and false otherwise.
==, !=, <, <=, >, >=
The comparison operators for smart pointers delegate to the operators of the underlying class, therefore the author of the reference-counted class defines the semantics of smart pointer comparison. For example, in the case of Slice classes, the base class Ice::Object
implements the comparison operators in terms of pointer addresses. On the other hand, the base class for Slice proxies implements comparison using value semantics.