Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/SharedPtr.h @ 10624

Last change on this file since 10624 was 10624, checked in by landauf, 9 years ago

merged branch core7 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 SharedPtr "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 ~SharedCounter() {}
166                virtual void destroy() = 0;
167
168                int count_;
169        };
170
171        /// Child class of SharedCounter, keeps a pointer to an object of type T that can be destroyed with destroy()
172        template <class T>
173        class SharedCounterImpl : public SharedCounter
174        {
175            public:
176                SharedCounterImpl(T* pointer) : pointer_(pointer) {}
177
178                void destroy()
179                {
180                    delete this->pointer_;
181                }
182
183            private:
184                T* pointer_;
185        };
186
187        _UtilExport SmallObjectAllocator& createSharedCounterPool();
188
189        ORX_FORCEINLINE SmallObjectAllocator& getSharedCounterPool()
190        {
191            static SmallObjectAllocator& instance = createSharedCounterPool();
192            return instance;
193        }
194    }
195
196    /**
197        @brief The SharedPtr template is a utility to manage pointers to an object.
198        @param T The type of the managed object
199
200        SharedPtr acts like a real pointer, except that it keeps track of the number of
201        references to the object. If the the number of references drops to zero, the
202        object is destroyed automatically.
203
204        @see See @ref SharedPtrExample "this description" for some examples and more information.
205
206        @note The number of references is stored in a separate object that is shared
207        among all instances of SharedPtr that point to the same pointer. This object is
208        also responsible for destroying the pointer if the reference counter becomes zero.
209    */
210    template <class T>
211    class SharedPtr
212    {
213        template <class O>
214        friend class SharedPtr;
215
216        public:
217            /// Default constructor, the pointer is set to NULL.
218            inline SharedPtr() : pointer_(0), counter_(0)
219            {
220            }
221
222            /// Constructor, creates a SharedPtr that points to @a pointer, increments the counter.
223            inline SharedPtr(T* pointer) : pointer_(pointer), counter_(0)
224            {
225                if (this->pointer_)
226                {
227                    void* chunk = detail::getSharedCounterPool().alloc();
228                    this->counter_ = new (chunk) detail::SharedCounterImpl<T>(this->pointer_);
229                }
230            }
231
232            /// Copy-constructor, this SharedPtr now points to the same object like the other SharedPtr, increments the counter.
233            inline SharedPtr(const SharedPtr& other) : pointer_(other.pointer_), counter_(other.counter_)
234            {
235                if (this->pointer_)
236                    ++this->counter_->count_;
237            }
238
239            /// Copy-constructor for SharedPtr with another template agument, increments the counter.
240            template <class O>
241            inline SharedPtr(const SharedPtr<O>& other) : pointer_(other.pointer_), counter_(other.counter_)
242            {
243                if (this->pointer_)
244                    ++this->counter_->count_;
245            }
246
247            /// Destructor, decrements the counter and deletes the object if the counter becomes zero.
248            inline ~SharedPtr()
249            {
250                if (this->pointer_)
251                {
252                    --this->counter_->count_;
253
254                    if (this->counter_->count_ == 0)
255                    {
256                        this->counter_->destroy();
257                        detail::getSharedCounterPool().free(this->counter_);
258                    }
259                }
260            }
261
262            /// Assigns a new object, decrements the counter of the old object, increments the counter of the new object.
263            inline SharedPtr& operator=(const SharedPtr& other)
264            {
265                SharedPtr(other).swap(*this);
266                return *this;
267            }
268
269            /// Assigns a new object with another template argument, decrements the counter of the old object, increments the counter of the new object.
270            template <class O>
271            inline SharedPtr& operator=(const SharedPtr<O>& other)
272            {
273                SharedPtr(other).swap(*this);
274                return *this;
275            }
276
277            /// Casts the pointer to another type
278            template <class O>
279            inline SharedPtr<O> cast() const
280            {
281                O* temp = static_cast<O*>(this->pointer_); // temp value for prettier compiler error in case of an invalid static_cast
282                return SharedPtr<O>(temp, this->counter_);
283            }
284
285            /// Overloaded -> operator, returns the pointer to the managed object.
286            inline T* operator->() const
287            {
288                assert(this->pointer_ != 0);
289                return this->pointer_;
290            }
291
292            /// Overloaded * operator, returns a reference ot the managed object.
293            inline T& operator*() const
294            {
295                assert(this->pointer_ != 0);
296                return *this->pointer_;
297            }
298
299            /// Returns the pointer to the managed object.
300            inline T* get() const
301            {
302                return this->pointer_;
303            }
304
305            /// Returns true if the pointer is not NULL.
306            inline operator bool() const
307            {
308                return (this->pointer_ != 0);
309            }
310
311            /// Swaps the pointer and the counter of two instances of SharedPtr with the same template argument.
312            inline void swap(SharedPtr& other)
313            {
314                std::swap(this->pointer_, other.pointer_);
315                std::swap(this->counter_, other.counter_);
316            }
317
318        private:
319            /// Private constructor, used by the cast() function.
320            inline SharedPtr(T* pointer, detail::SharedCounter* counter) : pointer_(pointer), counter_(counter)
321            {
322                if (this->pointer_)
323                    ++this->counter_->count_;
324            }
325
326            T* pointer_;                        ///< A pointer to the managed object of type @a T
327            detail::SharedCounter* counter_;    ///< A pointer to the shared reference counter
328    };
329
330    /**
331        @brief A child class of SharedPtr, used to reflect the hierarchy of the underlying class @a T.
332        @param T The type of the managed object
333        @param Parent The type of the SharedPtr that manages the parent class of @a T
334
335        This class is used to reflect the hierarchy of the underlying class @a T.
336        For example the @c Functor classes: While a @c Functor* pointer would be managed by
337        @c SharedPtr<Functor>, the child class @c FunctorStatic is managed by the class
338        <tt>SharedChildPtr<FunctorStatic, SharedPtr<Functor> ></tt>.
339
340        The second template argument @a Parent is used as the parent class of
341        SharedChildPtr. This means that each instance of <tt>SharedChildPtr<T, Parent></tt>
342        can be upcasted to @c Parent.
343
344        So for example this works:
345        @code
346        SharedChildPtr<FunctorStatic, SharedPtr<Functor> > functorStatic = createFunctor(&MyClass::myStaticFunction);
347        SharedPtr<Functor> functor = functorStatic;
348        @endcode
349
350        @note There are some typedefs and more to make the usage of SharedChildPtr easier
351        for the classes Functor and Executor. See FunctorPtr.h and ExecutorPtr.h. The above
352        example could thus be simplified the following way:
353        @code
354        FunctorStaticPtr functorStatic = createFunctor(&MyClass::myStaticFunction);
355        FunctorPtr functor = functorStatic;
356        @endcode
357
358        @see See SharedPtr for more information about the base class SharedPtr.
359        @see See @ref SharedPtrExample "this description" for some examples about how to use SharedPtr.
360    */
361    template <class T, class Parent>
362    class SharedChildPtr : public Parent
363    {
364        public:
365            inline SharedChildPtr() : Parent() {}
366            inline SharedChildPtr(T* pointer) : Parent(pointer) {}
367            inline SharedChildPtr(const SharedPtr<T>& other) : Parent(other) {}
368
369            inline T* operator->() const { return static_cast<T*>(Parent::operator->()); }
370            inline T& operator*() const { return *static_cast<T*>(Parent::operator->()); }
371    };
372
373}
374
375#endif /* _SharedPtr_H__ */
Note: See TracBrowser for help on using the repository browser.