refcnt.hh (8220:d9f19c39ddba) refcnt.hh (8221:8b5f900233ee)
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;

--- 17 unchanged lines hidden (view full) ---

26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 */
30
31#ifndef __BASE_REFCNT_HH__
32#define __BASE_REFCNT_HH__
33
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;

--- 17 unchanged lines hidden (view full) ---

26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 */
30
31#ifndef __BASE_REFCNT_HH__
32#define __BASE_REFCNT_HH__
33
34/**
35 * @file base/refcnt.hh
36 *
37 * Classes for managing reference counted objects.
38 */
39
40/**
41 * Derive from RefCounted if you want to enable reference counting of
42 * this class. If you want to use automatic reference counting, you
43 * should use RefCountingPtr<T> instead of regular pointers.
44 */
34class RefCounted
35{
36 private:
45class RefCounted
46{
47 private:
48 // The reference count is mutable because one may want to
49 // reference count a const pointer. This really is OK because
50 // const is about logical constness of the object not really about
51 // strictly disallowing an object to change.
37 mutable int count;
38
39 private:
40 // Don't allow a default copy constructor or copy operator on
41 // these objects because the default operation will copy the
42 // reference count as well and we certainly don't want that.
43 RefCounted(const RefCounted &);
44 RefCounted &operator=(const RefCounted &);
45
46 public:
52 mutable int count;
53
54 private:
55 // Don't allow a default copy constructor or copy operator on
56 // these objects because the default operation will copy the
57 // reference count as well and we certainly don't want that.
58 RefCounted(const RefCounted &);
59 RefCounted &operator=(const RefCounted &);
60
61 public:
62 /**
63 * We initialize the reference count to zero and the first object
64 * to take ownership of it must increment it to one.
65 *
66 * @attention A memory leak will occur if you never assign a newly
67 * constructed object to a reference counting pointer.
68 */
47 RefCounted() : count(0) {}
69 RefCounted() : count(0) {}
70
71 /**
72 * We make the destructor virtual because we're likely to have
73 * virtual functions on reference counted objects.
74 *
75 * @todo Even if this were true, does it matter? Shouldn't the
76 * derived class indicate this? This only matters if we would
77 * ever choose to delete a "RefCounted *" which I doubt we'd ever
78 * do. We don't ever delete a "void *".
79 */
48 virtual ~RefCounted() {}
49
80 virtual ~RefCounted() {}
81
82 /// Increment the reference count
50 void incref() { ++count; }
83 void incref() { ++count; }
84
85 /// Decrement the reference count and destroy the object if all
86 /// references are gone.
51 void decref() { if (--count <= 0) delete this; }
52};
53
87 void decref() { if (--count <= 0) delete this; }
88};
89
90/**
91 * If you want a reference counting pointer to a mutable object,
92 * create it like this:
93 * @code
94 * typedef RefCountingPtr<Foo> FooPtr;
95 * @endcode
96 *
97 * @attention Do not use "const FooPtr"
98 * To create a reference counting pointer to a const object, use this:
99 * @code
100 * typedef RefCountingPtr<const Foo> ConstFooPtr;
101 * @endcode
102 *
103 * These two usages are analogous to iterator and const_iterator in the stl.
104 */
54template <class T>
55class RefCountingPtr
56{
57 protected:
105template <class T>
106class RefCountingPtr
107{
108 protected:
109 /// The stored pointer.
110 /// Arguably this should be private.
58 T *data;
59
111 T *data;
112
60 void copy(T *d)
113 /**
114 * Copy a new pointer value and increment the reference count if
115 * it is a valid pointer. Note, this does not delete the
116 * reference any existing object.
117 * @param d Pointer to store.
118 */
119 void
120 copy(T *d)
61 {
62 data = d;
63 if (data)
64 data->incref();
65 }
121 {
122 data = d;
123 if (data)
124 data->incref();
125 }
66 void del()
126
127 /**
128 * Delete the reference to any existing object if it is non NULL.
129 * @attention this doesn't clear the pointer value, so a double
130 * decref could happen if not careful.
131 */
132 void
133 del()
67 {
68 if (data)
69 data->decref();
70 }
134 {
135 if (data)
136 data->decref();
137 }
71 void set(T *d)
72 {
73 if (data == d)
74 return;
75
138
76 del();
77 copy(d);
139 /**
140 * Drop the old reference and change it to something new.
141 */
142 void
143 set(T *d)
144 {
145 // Need to check if we're actually changing because otherwise
146 // we could delete the last reference before adding the new
147 // reference.
148 if (data != d) {
149 del();
150 copy(d);
151 }
78 }
79
152 }
153
80
81 public:
154 public:
155 /// Create an empty reference counting pointer.
82 RefCountingPtr() : data(0) {}
156 RefCountingPtr() : data(0) {}
157
158 /// Create a new reference counting pointer to some object
159 /// (probably something newly created). Adds a reference.
83 RefCountingPtr(T *data) { copy(data); }
160 RefCountingPtr(T *data) { copy(data); }
161
162 /// Create a new reference counting pointer by copying another
163 /// one. Adds a reference.
84 RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
164 RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
165
166 /// Destroy the pointer and any reference it may hold.
85 ~RefCountingPtr() { del(); }
86
167 ~RefCountingPtr() { del(); }
168
169 // The following pointer access functions are const because they
170 // don't actually change the pointer, though the user could change
171 // what is pointed to. This is analagous to a "Foo * const".
172
173 /// Access a member variable.
87 T *operator->() const { return data; }
174 T *operator->() const { return data; }
175
176 /// Dereference the pointer.
88 T &operator*() const { return *data; }
177 T &operator*() const { return *data; }
178
179 /// Directly access the pointer itself without taking a reference.
89 T *get() const { return data; }
90
180 T *get() const { return data; }
181
182 /// Assign a new value to the pointer
91 const RefCountingPtr &operator=(T *p) { set(p); return *this; }
183 const RefCountingPtr &operator=(T *p) { set(p); return *this; }
184
185 /// Copy the pointer from another RefCountingPtr
92 const RefCountingPtr &operator=(const RefCountingPtr &r)
93 { return operator=(r.data); }
94
186 const RefCountingPtr &operator=(const RefCountingPtr &r)
187 { return operator=(r.data); }
188
189 /// Check if the pointer is empty
95 bool operator!() const { return data == 0; }
190 bool operator!() const { return data == 0; }
191
192 /// Check if the pointer is non-empty
96 operator bool() const { return data != 0; }
97};
98
193 operator bool() const { return data != 0; }
194};
195
196/// Check for equality of two reference counting pointers.
99template<class T>
100inline bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
101{ return l.get() == r.get(); }
102
197template<class T>
198inline bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
199{ return l.get() == r.get(); }
200
201/// Check for equality of of a reference counting pointers and a
202/// regular pointer
103template<class T>
104inline bool operator==(const RefCountingPtr<T> &l, const T *r)
105{ return l.get() == r; }
106
203template<class T>
204inline bool operator==(const RefCountingPtr<T> &l, const T *r)
205{ return l.get() == r; }
206
207/// Check for equality of of a reference counting pointers and a
208/// regular pointer
107template<class T>
108inline bool operator==(const T *l, const RefCountingPtr<T> &r)
109{ return l == r.get(); }
110
209template<class T>
210inline bool operator==(const T *l, const RefCountingPtr<T> &r)
211{ return l == r.get(); }
212
213/// Check for inequality of two reference counting pointers.
111template<class T>
112inline bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
113{ return l.get() != r.get(); }
114
214template<class T>
215inline bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
216{ return l.get() != r.get(); }
217
218/// Check for inequality of of a reference counting pointers and a
219/// regular pointer
115template<class T>
116inline bool operator!=(const RefCountingPtr<T> &l, const T *r)
117{ return l.get() != r; }
118
220template<class T>
221inline bool operator!=(const RefCountingPtr<T> &l, const T *r)
222{ return l.get() != r; }
223
224/// Check for inequality of of a reference counting pointers and a
225/// regular pointer
119template<class T>
120inline bool operator!=(const T *l, const RefCountingPtr<T> &r)
121{ return l != r.get(); }
122
123#endif // __BASE_REFCNT_HH__
226template<class T>
227inline bool operator!=(const T *l, const RefCountingPtr<T> &r)
228{ return l != r.get(); }
229
230#endif // __BASE_REFCNT_HH__