Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/object/SmartPtr.h @ 9890

Last change on this file since 9890 was 9571, checked in by landauf, 12 years ago

using Destroyable instead of OrxonoxClass now wherever the destruction-related members are addressed

  • Property svn:eol-style set to native
File size: 11.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29// Inspired by boost::intrusive_ptr by Peter Dimov
30
31/**
32    @defgroup SmartPtr SmartPtr<T> and WeakPtr<T>
33    @ingroup Object
34*/
35
36/**
37    @file
38    @ingroup Object SmartPtr
39    @brief Definition of SmartPtr<T>, wraps a pointer to an object and keeps it alive.
40
41    @anchor SmartPtrExample
42
43    orxonox::SmartPtr is an implementation of a smart pointer - it wraps a pointer to an
44    object  and keeps this object alive until no SmartPtr points to this object anymore.
45    In contrast to orxonox::SharedPtr, SmartPtr works only with classes that are derived
46    from orxonox::Destroyable, because it's an intrusive implementation, meaning the
47    reference counter is stored in the object itself.
48
49    It's possible to use normal pointers and smart pointers to an object simultaneously.
50    You don't have to use SmartPtr all the time, you can create a SmartPtr for an object
51    at any time and also convert it back to a normal pointer if you like. This is possible
52    because the reference counter is stored in the object itself and not in SmartPtr (in
53    contrast to SharedPtr).
54
55    @b Important: If you want to delete an object, you must not use @c delete @c object but
56    rather @c object->destroy(). This function will check if there are smart pointers
57    pointing to the object. If yes, the object will be kept alive until all smart pointes
58    are destroyed. If no, the object is deleted instantly.
59
60    If all smart pointers that point to an object are destroyed, but you never called
61    @c object->destroy() before, the object will not be deleted! All a SmartPtr will do
62    is to really just keep an object alive, but it will not delete it automatically
63    unless you tried to destroy it before.
64
65    Example:
66    @code
67    class MyClass                                           // class declaration
68    {
69        public:
70            void setObject(OtherClass* object)              // passes a normal pointer which will be stored in a SmartPtr
71                { this->object_ = object; }
72
73            OtherClass* getObject() const                   // converts the SmartPtr to a normal pointer and returns it
74                { return this->object_; }
75
76        private:
77            SmartPtr<OtherClass> object_;                   // a pointer to an instance of OtherClass is stored in a SmartPtr
78    };
79    @endcode
80    In this example we assume that OtherClass is a child of Destroyable. We don't care
81    about the inheritance of MyClass though.
82
83    Now we create an instance of MyClass and assign a pointer to an instance of OtherClass:
84    @code
85    MyClass* myclass = new MyClass();                       // create an instance of MyClass
86    OtherClass* object = new OtherClass();                  // create an instance of OtherClass
87    myclass->setObject(object);                             // the object is now stored in a SmartPtr inside myclass
88
89    object->destroy();                                      // we try to destroy object, but there's still a SmartPtr pointing at it.
90
91    # object still exists at this point (because a SmartPtr points at it)
92
93    delete myclass;                                         // now we delete myclass, which also destroys the SmartPtr
94
95    # object doesn't exist anymore (because the SmartPtr is now destroyed)
96    @endcode
97
98    Now we look at the same example, but we first delete myclass, then destroy object:
99    @code
100    MyClass* myclass = new MyClass();                       // create an instance of MyClass
101    OtherClass* object = new OtherClass();                  // create an instance of OtherClass
102    myclass->setObject(object);                             // the object is now stored in a SmartPtr inside myclass
103
104    delete myclass;                                         // we delete myclass, which also destroys the SmartPtr
105
106    # object still exists at this point (because destroy() was not called yet)
107
108    object->destroy();                                      // now we try to destroy object, which works instantly
109
110    # object doesn't exist anymore (because we just destroyed it)
111    @endcode
112
113    Note that in any case @c object->destroy() has to be called to delete the object.
114    However if a SmartPtr points at it, the destruction is delayed until all SmartPtr
115    are destroyed.
116*/
117
118#ifndef _SmartPtr_H__
119#define _SmartPtr_H__
120
121#include "core/CorePrereqs.h"
122
123#include <cassert>
124
125#include "core/object/Destroyable.h"
126#include "WeakPtr.h"
127
128namespace orxonox
129{
130    /**
131        @brief A smart pointer which wraps a pointer to an object and keeps this object alive as long as the smart pointer exists.
132
133        @see See @ref SmartPtrExample "this description" for more information and an example.
134    */
135    template <class T>
136    class SmartPtr
137    {
138        public:
139            /// Constructor: Initializes the smart pointer with a null pointer.
140            inline SmartPtr() : pointer_(0), base_(0)
141            {
142            }
143
144            /// Constructor: Used to explicitly initialize the smart pointer with a null pointer
145            inline SmartPtr(int) : pointer_(0), base_(0)
146            {
147            }
148
149            /// Constructor: Initializes the smart pointer with a pointer to an object. @param pointer The pointer @param bAddRef If true, the reference counter is increased. Don't set this to false unless you know exactly what you're doing! (for example to avoid circular references if the @c this pointer of the possessing object is stored)
150            inline SmartPtr(T* pointer, bool bAddRef = true) : pointer_(pointer), base_(pointer)
151            {
152                if (this->base_ && bAddRef)
153                    this->base_->incrementReferenceCount();
154            }
155
156            /// Copy-constructor
157            inline SmartPtr(const SmartPtr& other) : pointer_(other.pointer_), base_(other.base_)
158            {
159                if (this->base_)
160                    this->base_->incrementReferenceCount();
161            }
162
163            /// Copy-constructor for smart pointers to objects of another class.
164            template <class O>
165            inline SmartPtr(const SmartPtr<O>& other) : pointer_(other.get()), base_(other.base_)
166            {
167                if (this->base_)
168                    this->base_->incrementReferenceCount();
169            }
170
171            /// Constructor: Initializes the smart pointer with the pointer that is stored in a WeakPtr.
172            template <class O>
173            inline SmartPtr(const WeakPtr<O>& other) : pointer_(other.get()), base_(other.getBase())
174            {
175                if (this->base_)
176                    this->base_->incrementReferenceCount();
177            }
178
179            /// Destructor: Decrements the reference counter.
180            inline ~SmartPtr()
181            {
182                if (this->base_)
183                    this->base_->decrementReferenceCount();
184            }
185
186            /// Used to assign a null pointer.
187            inline SmartPtr& operator=(int)
188            {
189                SmartPtr(0).swap(*this);
190                return *this;
191            }
192
193            /// Assigns a new pointer.
194            inline SmartPtr& operator=(T* pointer)
195            {
196                SmartPtr(pointer).swap(*this);
197                return *this;
198            }
199
200            /// Assigns the wrapped pointer of another SmartPtr.
201            inline SmartPtr& operator=(const SmartPtr& other)
202            {
203                SmartPtr(other).swap(*this);
204                return *this;
205            }
206
207            /// Assigns the wrapped pointer of a SmartPtr of another class
208            template <class O>
209            inline SmartPtr& operator=(const SmartPtr<O>& other)
210            {
211                SmartPtr(other).swap(*this);
212                return *this;
213            }
214
215            /// Assigns the wrapped pointer of a WeakPtr.
216            template <class O>
217            inline SmartPtr& operator=(const WeakPtr<O>& other)
218            {
219                SmartPtr(other).swap(*this);
220                return *this;
221            }
222
223            /// Returns the wrapped pointer as @c T*
224            inline T* get() const
225            {
226                return this->pointer_;
227            }
228
229            /// Returns the wrapped pointer as @c Destroyable*
230            inline Destroyable* getBase() const
231            {
232                return this->base_;
233            }
234
235            /// Implicitly converts the SmartPtr to a pointer of type @c T*
236            inline operator T*() const
237            {
238                return this->pointer_;
239            }
240
241            /// Overloaded operator, returns a pointer to the stored object.
242            inline T* operator->() const
243            {
244                assert(this->pointer_ != 0);
245                return this->pointer_;
246            }
247
248            /// Overloaded operator, returns a reference to the stored object.
249            inline T& operator*() const
250            {
251                assert(this->pointer_ != 0);
252                return *this->pointer_;
253            }
254
255            /// Returns true if the wrapped pointer is NULL.
256            inline bool operator!() const
257            {
258                return (this->pointer_ == 0);
259            }
260
261            /// Swaps the contents of two smart pointers.
262            inline void swap(SmartPtr& other)
263            {
264                {
265                    T* temp = this->pointer_;
266                    this->pointer_ = other.pointer_;
267                    other.pointer_ = temp;
268                }
269                {
270                    Destroyable* temp = this->base_;
271                    this->base_ = other.base_;
272                    other.base_ = temp;
273                }
274            }
275
276            /// Resets the smart pointer (equivalent to assigning a NULL pointer).
277            inline void reset()
278            {
279                SmartPtr().swap(*this);
280            }
281
282        private:
283            T* pointer_;            ///< The wrapped pointer to an object of type @a T
284            Destroyable* base_;    ///< The wrapped pointer, casted up to Destroyable (this is needed because with just a T* pointer, SmartPtr couln't be used with forward declarations)
285    };
286
287    /// Swaps the contents of two smart pointers.
288    template <class T>
289    void swap(SmartPtr<T>& a, SmartPtr<T>& b)
290    {
291        a.swap(b);
292    }
293
294    /// Uses a static_cast to cast a pointer of type U* to a pointer of type T* and returns it in a new SmartPtr<T>.
295    template <class T, class U>
296    SmartPtr<T> static_pointer_cast(const SmartPtr<U>& p)
297    {
298        return static_cast<T*>(p.get());
299    }
300
301    /// Uses a const_cast to cast a pointer of type U* to a pointer of type T* and returns it in a new SmartPtr<T>.
302    template <class T, class U>
303    SmartPtr<T> const_pointer_cast(const SmartPtr<U>& p)
304    {
305        return const_cast<T*>(p.get());
306    }
307
308    /// Uses a dynamic_cast to cast a pointer of type U* to a pointer of type T* and returns it in a new SmartPtr<T>.
309    template <class T, class U>
310    SmartPtr<T> dynamic_pointer_cast(const SmartPtr<U>& p)
311    {
312        return orxonox_cast<T*>(p.get());
313    }
314}
315
316#endif /* _SmartPtr_H__ */
Note: See TracBrowser for help on using the repository browser.