Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutorial/src/libraries/util/SharedPtr.h @ 9268

Last change on this file since 9268 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

  • Property svn:eol-style set to native
File size: 14.0 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/**
30    @defgroup SharedPtr SharedPtr<T>
31    @ingroup Util
32*/
33
34/**
35    @file
36    @ingroup SharedPtr
37    @brief Definition of the SharedPtr template that is used to manage pointers.
38
39    @anchor SharedPtrExample
40
41    The orxonox::SharedPtr template can be used to manage a pointer to an object
42    that was created with new. The SharedPtr acts like the pointer itself, but it
43    keeps track of the number of references to it. If all references are removed,
44    SharedPtr deletes the managed object automatically.
45
46    Example:
47
48    Classic implementation using new and delete:
49    @code
50    void someFunction()
51    {
52        MyClass* object = new MyClass();            // Create a new instance of MyClass
53
54        object->myFunction();                       // Calls MyClass::myFunction()
55
56        delete object;                              // Delete the object at the end of the scope
57    }
58    @endcode
59
60    The same function using SharedPtr:
61    @code
62    void someFunction()
63    {
64        SharedPtr<MyClass> object = new MyClass();  // Create a new instance of MyClass and store its pointer in a SharedPtr
65
66        object->myFunction();                       // Calls MyClass::myFunction()
67
68    }                                               // At the end of the scope, the SharedPtr is destroyed. Because no other SharedPtrs
69                                                    // point at the object, the object itself is also destroyed automatically
70    @endcode
71
72    This is especially handy if you do not know what will happen with an object that was
73    created with new, for example if you pass it to another object. If multiple instances
74    share a pointer to the same object, none of these instances can delete the object
75    without interfering with the other instances. But if none of the instances destroy the
76    object, it will never be destroyed and results in a memory leak. With a SharedPtr
77    however you don't have to think about destroying the object, because the SharedPtr
78    itself keeps track of the references.
79
80    Example:
81
82    Classic implementation using new and delete:
83    @code
84    class OtherClass                                    // Declaration of some class
85    {
86        public:
87            OtherClass(MyClass* object)                 // Constructor
88            {
89                this->object_ = object;                 // Assigns the pointer to the member variable object_
90            }
91
92            ~OtherClass()                               // Destructor
93            {
94                ???                                     // What to do with object_?
95            }
96
97        private:
98            MyClass* object_;                           // A pointer to the object
99    };
100
101    void someFunction()
102    {
103        MyClass* object = new MyClass();                // Create a new instance of MyClass
104
105        OtherClass* other1 = new OtherClass(object);    // Create an instance of OtherClass and pass the object pointer
106        OtherClass* other2 = new OtherClass(object);    // "
107        OtherClass* other3 = new OtherClass(object);    // "
108
109        ???                                             // What happens with object now?
110    }
111    @endcode
112
113    If you use SharedPtr<MyClass> instead of a classic MyClass* pointer, the instance of
114    MyClass would be automatically destroyed if all instances of OtherClass are destroyed.
115    You don't need any code in the destructor and you can completely forget about the
116    object, because its managed by the SharedPtr.
117
118    The same code using SharedPtr:
119    @code
120    class OtherClass                                        // Declaration of some class
121    {
122        public:
123            OtherClass(const SharedPtr<MyClass>& object)    // Constructor
124            {
125                this->object_ = object;                     // Assigns the pointer to the member variable object_
126            }
127
128        private:
129            SharedPtr<MyClass> object_;                     // A SharedPtr to the object
130    };
131
132    void someFunction()
133    {
134        SharedPtr<MyClass> object = new MyClass();          // Create a new instance of MyClass
135
136        OtherClass* other1 = new OtherClass(object);        // Create an instance of OtherClass and pass the object pointer
137        OtherClass* other2 = new OtherClass(object);        // "
138        OtherClass* other3 = new OtherClass(object);        // "
139
140    }                                                       // The SmartPtr "object" is destroyed at the end of the scope,
141                                                            // but the three instances of OtherClass keep the object alive
142                                                            // until they are all destroyed.
143    @endcode
144*/
145
146#ifndef _SharedPtr_H__
147#define _SharedPtr_H__
148
149#include "UtilPrereqs.h"
150
151#include <algorithm>
152#include <cassert>
153
154#include "SmallObjectAllocator.h"
155
156namespace orxonox
157{
158    namespace detail
159    {
160        /// BaseClass of SharedCounterImpl, has a counter that is initialized with 1
161        class SharedCounter
162        {
163            public:
164                SharedCounter() : count_(1) {}
165                virtual void destroy() = 0;
166
167                int count_;
168        };
169
170        /// Child class of SharedCounter, keeps a pointer to an object of type T that can be destroyed with destroy()
171        template <class T>
172        class SharedCounterImpl : public SharedCounter
173        {
174            public:
175                SharedCounterImpl(T* pointer) : pointer_(pointer) {}
176
177                void destroy()
178                {
179                    delete this->pointer_;
180                }
181
182            private:
183                T* pointer_;
184        };
185
186        _UtilExport SmallObjectAllocator& createSharedCounterPool();
187
188        FORCEINLINE SmallObjectAllocator& getSharedCounterPool()
189        {
190            static SmallObjectAllocator& instance = createSharedCounterPool();
191            return instance;
192        }
193    }
194
195    /**
196        @brief The SharedPtr template is a utility to manage pointers to an object.
197        @param T The type of the managed object
198
199        SharedPtr acts like a real pointer, except that it keeps track of the number of
200        references to the object. If the the number of references drops to zero, the
201        object is destroyed automatically.
202
203        @see See @ref SharedPtrExample "this description" for some examples and more information.
204
205        @note The number of references is stored in a separate object that is shared
206        among all instances of SharedPtr that point to the same pointer. This object is
207        also responsible for destroying the pointer if the reference counter becomes zero.
208    */
209    template <class T>
210    class SharedPtr
211    {
212        template <class O>
213        friend class SharedPtr;
214
215        public:
216            /// Default constructor, the pointer is set to NULL.
217            inline SharedPtr() : pointer_(0), counter_(0)
218            {
219            }
220
221            /// Constructor, creates a SharedPtr that points to @a pointer, increments the counter.
222            inline SharedPtr(T* pointer) : pointer_(pointer), counter_(0)
223            {
224                if (this->pointer_)
225                {
226                    void* chunk = detail::getSharedCounterPool().alloc();
227                    this->counter_ = new (chunk) detail::SharedCounterImpl<T>(this->pointer_);
228                }
229            }
230
231            /// Copy-constructor, this SharedPtr now points to the same object like the other SharedPtr, increments the counter.
232            inline SharedPtr(const SharedPtr& other) : pointer_(other.pointer_), counter_(other.counter_)
233            {
234                if (this->pointer_)
235                    ++this->counter_->count_;
236            }
237
238            /// Copy-constructor for SharedPtr with another template agument, increments the counter.
239            template <class O>
240            inline SharedPtr(const SharedPtr<O>& other) : pointer_(other.pointer_), counter_(other.counter_)
241            {
242                if (this->pointer_)
243                    ++this->counter_->count_;
244            }
245
246            /// Destructor, decrements the counter and deletes the object if the counter becomes zero.
247            inline ~SharedPtr()
248            {
249                if (this->pointer_)
250                {
251                    --this->counter_->count_;
252
253                    if (this->counter_->count_ == 0)
254                    {
255                        this->counter_->destroy();
256                        detail::getSharedCounterPool().free(this->counter_);
257                    }
258                }
259            }
260
261            /// Assigns a new object, decrements the counter of the old object, increments the counter of the new object.
262            inline SharedPtr& operator=(const SharedPtr& other)
263            {
264                SharedPtr(other).swap(*this);
265                return *this;
266            }
267
268            /// Assigns a new object with another template argument, decrements the counter of the old object, increments the counter of the new object.
269            template <class O>
270            inline SharedPtr& operator=(const SharedPtr<O>& other)
271            {
272                SharedPtr(other).swap(*this);
273                return *this;
274            }
275
276            /// Casts the pointer to another type
277            template <class O>
278            inline SharedPtr<O> cast() const
279            {
280                O* temp = static_cast<O*>(this->pointer_); // temp value for prettier compiler error in case of an invalid static_cast
281                return SharedPtr<O>(temp, this->counter_);
282            }
283
284            /// Overloaded -> operator, returns the pointer to the managed object.
285            inline T* operator->() const
286            {
287                assert(this->pointer_ != 0);
288                return this->pointer_;
289            }
290
291            /// Overloaded * operator, returns a reference ot the managed object.
292            inline T& operator*() const
293            {
294                assert(this->pointer_ != 0);
295                return *this->pointer_;
296            }
297
298            /// Returns the pointer to the managed object.
299            inline T* get() const
300            {
301                return this->pointer_;
302            }
303
304            /// Returns true if the pointer is not NULL.
305            inline operator bool() const
306            {
307                return (this->pointer_ != 0);
308            }
309
310            /// Swaps the pointer and the counter of two instances of SharedPtr with the same template argument.
311            inline void swap(SharedPtr& other)
312            {
313                std::swap(this->pointer_, other.pointer_);
314                std::swap(this->counter_, other.counter_);
315            }
316
317        private:
318            /// Private constructor, used by the cast() function.
319            inline SharedPtr(T* pointer, detail::SharedCounter* counter) : pointer_(pointer), counter_(counter)
320            {
321                if (this->pointer_)
322                    ++this->counter_->count_;
323            }
324
325            T* pointer_;                        ///< A pointer to the managed object of type @a T
326            detail::SharedCounter* counter_;    ///< A pointer to the shared reference counter
327    };
328
329    /**
330        @brief A child class of SharedPtr, used to reflect the hierarchy of the underlying class @a T.
331        @param T The type of the managed object
332        @param Parent The type of the SharedPtr that manages the parent class of @a T
333
334        This class is used to reflect the hierarchy of the underlying class @a T.
335        For example the @c Functor classes: While a @c Functor* pointer would be managed by
336        @c SharedPtr<Functor>, the child class @c FunctorStatic is managed by the class
337        <tt>SharedChildPtr<FunctorStatic, SharedPtr<Functor> ></tt>.
338
339        The second template argument @a Parent is used as the parent class of
340        SharedChildPtr. This means that each instance of <tt>SharedChildPtr<T, Parent></tt>
341        can be upcasted to @c Parent.
342
343        So for example this works:
344        @code
345        SharedChildPtr<FunctorStatic, SharedPtr<Functor> > functorStatic = createFunctor(&MyClass::myStaticFunction);
346        SharedPtr<Functor> functor = functorStatic;
347        @endcode
348
349        @note There are some typedefs and more to make the usage of SharedChildPtr easier
350        for the classes Functor and Executor. See FunctorPtr.h and ExecutorPtr.h. The above
351        example could thus be simplified the following way:
352        @code
353        FunctorStaticPtr functorStatic = createFunctor(&MyClass::myStaticFunction);
354        FunctorPtr functor = functorStatic;
355        @endcode
356
357        @see See SharedPtr for more information about the base class SharedPtr.
358        @see See @ref SharedPtrExample "this description" for some examples about how to use SharedPtr.
359    */
360    template <class T, class Parent>
361    class SharedChildPtr : public Parent
362    {
363        public:
364            inline SharedChildPtr() : Parent() {}
365            inline SharedChildPtr(T* pointer) : Parent(pointer) {}
366            inline SharedChildPtr(const SharedPtr<T>& other) : Parent(other) {}
367
368            inline T* operator->() const { return static_cast<T*>(Parent::operator->()); }
369            inline T& operator*() const { return *static_cast<T*>(Parent::operator->()); }
370    };
371
372}
373
374#endif /* _SharedPtr_H__ */
Note: See TracBrowser for help on using the repository browser.