source: trunk/TEMPLATES/smartptr.h

Last change on this file was 18311, checked in by westram, 5 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1// --------------------------------------------------------------------------------
2// Copyright (C) 2000-2003
3// Ralf Westram
4// (Coded@ReallySoft.de)
5//
6// Permission to use, copy, modify, distribute and sell this software
7// and its documentation for any purpose is hereby granted without fee,
8// provided that the above copyright notice appear in all copies and
9// that both that copyright notice and this permission notice appear
10// in supporting documentation.  Ralf Westram makes no
11// representations about the suitability of this software for any
12// purpose.  It is provided "as is" without express or implied warranty.
13//
14// This code is part of my library.
15// You may find a more recent version at http://www.reallysoft.de/
16// --------------------------------------------------------------------------------
17
18#ifndef SMARTPTR_H
19#define SMARTPTR_H
20
21#ifndef ARB_ASSERT_H
22#include <arb_assert.h>
23#endif
24#ifndef ARBTOOLS_H
25#include "arbtools.h"
26#endif
27
28#define tpl_assert(bed) arb_assert(bed)
29
30// --------------------------------------------------------------------------------
31//     SmartPointers
32// --------------------------------------------------------------------------------
33//
34//  provides:
35//
36//  SmartPtr<type>                                                              uses delete
37//  SmartPtr<type, Counted<type, auto_delete_array_ptr<type> > >                uses delete []
38//  SmartPtr<type, Counted<type, auto_free_ptr<type> > >                        uses free
39//  SmartPtr<type, Counted<type, custom_dealloc_ptr<type, deallocator> > >      uses custom deallocator
40//
41// --------------------------------------------------------------------------------
42// macros for convenience:
43
44#define SmartArrayPtr(type)               SmartPtr<type, Counted<type, auto_delete_array_ptr<type> > >
45#define SmartMallocPtr(type)              SmartPtr<type, Counted<type, auto_free_ptr<type> > >
46#define SmartCustomPtr(type, deallocator) SmartPtr<type, Counted<type, custom_dealloc_ptr<type, deallocator> > >
47
48// --------------------------------------------------------------------------------
49// examples:
50//
51// typedef SmartPtr<std::string> StringPtr;
52// StringPtr s = new std::string("hello world");        // will be deallocated using delete
53//
54// typedef SmartArrayPtr(std::string) StringArrayPtr;
55// StringArrayPtr strings = new std::string[100];       // will be deallocated using delete []
56//
57// SmartCharPtr cp = ARB_strdup("hello world");         // will be deallocated using free()
58//
59// typedef SmartCustomPtr(GEN_position, GEN_free_position) GEN_position_Ptr;
60// GEN_position_Ptr gp = GEN_new_position(5, false); // will be deallocated using GEN_free_position()
61//
62// --------------------------------------------------------------------------------
63
64#ifdef NDEBUG
65#ifdef DUMP_SMART_PTRS
66#error Please do not define DUMP_SMART_PTRS in NDEBUG mode!
67#endif
68#endif
69
70#ifdef DUMP_SMART_PTRS
71#define DUMP_SMART_PTRS_DO(cmd) do { (cmd); } while (0)
72#else
73#define DUMP_SMART_PTRS_DO(cmd)
74#endif
75
76// -----------------------------------------------------------------
77//      helper pointer classes
78//
79// used by Counted<> to use correct method to destroy the contents
80// -----------------------------------------------------------------
81
82template<class T, void (*DEALLOC)(T*)>
83class custom_dealloc_ptr : virtual Noncopyable {
84    T *const thePointer;
85public:
86    custom_dealloc_ptr(T *p) : thePointer(p) {
87        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p now controlled by custom_dealloc_ptr\n", thePointer));
88    }
89    ~custom_dealloc_ptr() {
90        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p gets destroyed by custom_dealloc_ptr (using fun %p)\n", thePointer, DEALLOC));
91        DEALLOC(thePointer);
92    }
93
94    const T* getPointer() const { return thePointer; }
95    T* getPointer() { return thePointer; }
96};
97
98template <class T>
99class auto_free_ptr : virtual Noncopyable {
100    T *const thePointer;
101public:
102    auto_free_ptr(T *p) : thePointer(p) {
103        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p now controlled by auto_free_ptr\n", thePointer));
104    }
105    ~auto_free_ptr() {
106        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p gets destroyed by auto_free_ptr\n", thePointer));
107        free(thePointer);
108    }
109
110    const T* getPointer() const { return thePointer; }
111    T* getPointer() { return thePointer; }
112};
113
114template <class T>
115class auto_delete_ptr : virtual Noncopyable {
116    T *const thePointer;
117public:
118    auto_delete_ptr(T *p) : thePointer(p) {
119        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p now controlled by auto_delete_ptr\n", thePointer));
120    }
121    ~auto_delete_ptr() {
122        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p gets destroyed by auto_delete_ptr\n", thePointer));
123        delete thePointer;
124    }
125
126    const T* getPointer() const { return thePointer; }
127    T* getPointer() { return thePointer; }
128};
129
130template <class T>
131class auto_delete_array_ptr : virtual Noncopyable {
132    T *const thePointer;
133public:
134    auto_delete_array_ptr(T *p) : thePointer(p) {
135        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p now controlled by auto_delete_array_ptr\n", thePointer));
136    }
137    ~auto_delete_array_ptr() {
138        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p gets destroyed by auto_delete_array_ptr\n", thePointer));
139        delete [] thePointer;
140    }
141
142    const T* getPointer() const { return thePointer; }
143    T* getPointer() { return thePointer; }
144};
145
146// -----------------------
147//      class Counted
148
149template <class T, class C> class SmartPtr;
150
151template <class T, class AP>
152class Counted {
153    unsigned counter;
154    AP       pointer;
155
156public:
157
158    Counted(T *p) : counter(0), pointer(p) {
159        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p now controlled by Counted\n", getPointer()));
160        tpl_assert(p); // if you like to assign NULp, consider using SmartPtr::assign or SmartPtr::setNull
161    }
162#ifdef DEBUG
163    ~Counted() {
164        tpl_assert(counter==0);
165        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p gets destroyed by Counted\n", getPointer()));
166    }
167#endif
168
169    unsigned new_reference() {
170        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p gets new reference (now there are %i references)\n", getPointer(), counter+1));
171        return ++counter;
172    }
173    unsigned free_reference() {
174        DUMP_SMART_PTRS_DO(fprintf(stderr, "pointer %p looses a reference (now there are %i references)\n", getPointer(), counter-1));
175        tpl_assert(counter!=0);
176        return --counter;
177    }
178
179    const T* getPointer() const { return pointer.getPointer(); }
180    T* getPointer() { return pointer.getPointer(); }
181
182    friend class SmartPtr<T, Counted<T, AP> >;
183};
184
185
186/*! @class SmartPtr
187 * @brief Generic smart pointer
188 */
189
190template <class T, class C = Counted<T, auto_delete_ptr<T> > >
191// cppcheck-suppress noCopyConstructor (does not detect templated cctor)
192class SmartPtr {
193private:
194    C *object;
195
196    void Unbind() {
197        if (object && object->free_reference()==0) {
198            DUMP_SMART_PTRS_DO(fprintf(stderr, "Unbind() deletes Counted object %p (which hold pointer %p)\n", object, object->getPointer()));
199            delete object;
200        }
201        object = NULp;
202    }
203public:
204    //! build Smart-NULp-Ptr
205    SmartPtr() : object(NULp) {}
206
207    /*! build normal SmartPtr
208
209        by passing an object to a SmartPtr you loose the responsibility over the object
210        to the SmartPtr.
211        So you NEVER should free such an object manually.
212
213        @param p Pointer to any dynamically allocated object
214    */
215    SmartPtr(T *p) {
216        object = new C(p);
217        object->new_reference();
218    }
219
220    /*! destroy SmartPtr
221
222        object will not be destroyed as long as any other SmartPtr points to it
223    */
224    ~SmartPtr() { Unbind(); }
225
226    SmartPtr(const SmartPtr<T, C>& other) {
227        // cppcheck-suppress copyCtorPointerCopying (that's exactly what a SmartPtr is made for)
228        object = other.object;
229        if (object) object->new_reference();
230    }
231    SmartPtr<T, C>& operator=(const SmartPtr<T, C>& other) {
232        if (other.object) other.object->new_reference();
233        Unbind();
234        object = other.object;
235        return *this;
236    }
237
238    const T *operator->() const { tpl_assert(object); return object->getPointer(); }
239    T *operator->() { tpl_assert(object); return object->getPointer(); }
240
241    const T& operator*() const { tpl_assert(object); return *(object->getPointer()); }
242    T& operator*() { tpl_assert(object); return *(object->getPointer()); } // Note: to deref a NULp-SmartPtr, use SmartPtr::content()
243
244    //! test if SmartPtr is not NULp
245    bool isSet() const { return object; }
246
247    //! test if SmartPtr is NULp
248    bool isNull() const { return !isSet(); }
249
250    //! set SmartPtr to NULp
251    void setNull() { Unbind(); }
252
253    //! set SmartPtr to new content or NULp
254    void assign(T *p) {
255        Unbind();
256        if (p) {
257            object = new C(p);
258            object->new_reference();
259        }
260    }
261
262    //! convert SmartPtr to plain old pointer (also works if isNull())
263    const T* content() const {
264        return object ? object->getPointer() : NULp;
265    }
266
267    SmartPtr<T, C> deep_copy() const {
268        /*! create a deep copy of the object pointed to by the smart pointer.
269         *
270         * Afterwards there exist two equal copies of the object.
271         *
272         * @return SmartPtr to the new copy.
273         */
274        return SmartPtr<T, C>(new T(**this));
275    }
276
277    bool sameObject(const SmartPtr<T, C>& other) const {
278        /*! test if two SmartPtrs point to the same object
279         *
280         * (this is used for operators == and !=).
281         *
282         * if you like to compare the objects themselves use
283         * (*smart_ptr1 == *smart_ptr2)
284         *
285         * @return true if the SmartPtrs point to the same object
286         */
287        tpl_assert(object);
288        tpl_assert(other.object);
289        return object==other.object;
290    }
291
292    unsigned references() const {
293        return isSet() ? object->counter : 0;
294    }
295};
296
297template <class T, class C> bool operator==(const SmartPtr<T, C>& s1, const SmartPtr<T, C>& s2) {
298    return s1.sameObject(s2);
299}
300
301template <class T, class C> bool operator!=(const SmartPtr<T, C>& s1, const SmartPtr<T, C>& s2) {
302    return !s1.sameObject(s2);
303}
304
305// --------------------------
306//      convenience decls
307
308typedef SmartMallocPtr(char) SmartCharPtr;
309
310#define RETURN_LOCAL_ALLOC(mallocation)                         \
311    static SmartMallocPtr(typeof(*mallocation)) static_ptr;     \
312    static_ptr.assign(mallocation);                             \
313    return static_ptr.content();
314
315#define RETURN_ONETIME_ALLOC(allocated)                         \
316    static SmartMallocPtr(typeof(*allocated)) static_ptr;       \
317    if (static_ptr.isNull()) { static_ptr = allocated; }        \
318    return static_ptr.content();
319
320#else
321#error smartptr.h included twice
322#endif // SMARTPTR_H
Note: See TracBrowser for help on using the repository browser.