annotate src/Support/linked_ptr.h @ 648:1c2a5868f23a

Fix memory leak in CARFAC. Also get rid of most uses of auto, which tend to hurt readability unless the type name is particularly long, especially when it masks pointers.
author ronw@google.com
date Tue, 11 Jun 2013 21:41:53 +0000
parents 79d5cbc09484
children
rev   line source
tomwalters@123 1 // Copyright (c) 2003 Google Inc.
tomwalters@123 2 //
tomwalters@123 3 // Permission is hereby granted, free of charge, to any person or organization
tomwalters@123 4 // obtaining a copy of the software and accompanying documentation covered by
tomwalters@123 5 // this license (the "Software") to use, reproduce, display, distribute,
tomwalters@123 6 // execute, and transmit the Software, and to prepare derivative works of the
tomwalters@123 7 // Software, and to permit third-parties to whom the Software is furnished to
tomwalters@123 8 // do so, all subject to the following:
tomwalters@123 9 //
tomwalters@123 10 // The copyright notices in the Software and this entire statement, including
tomwalters@123 11 // the above license grant, this restriction and the following disclaimer,
tomwalters@123 12 // must be included in all copies of the Software, in whole or in part, and
tomwalters@123 13 // all derivative works of the Software, unless such copies or derivative
tomwalters@123 14 // works are solely in the form of machine-executable object code generated by
tomwalters@123 15 // a source language processor.
tomwalters@123 16 //
tomwalters@123 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
tomwalters@123 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
tomwalters@123 19 // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
tomwalters@123 20 // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
tomwalters@123 21 // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
tomwalters@123 22 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
tomwalters@123 23 // DEALINGS IN THE SOFTWARE.
tomwalters@123 24 //
tomwalters@123 25 // linked_ptr.h
tomwalters@123 26 // Author: Dan Egnor
tomwalters@123 27 //
tomwalters@123 28 // A "smart" pointer type with reference tracking. Every pointer to a
tomwalters@123 29 // particular object is kept on a circular linked list. When the last pointer
tomwalters@123 30 // to an object is destroyed or reassigned, the object is deleted.
tomwalters@123 31 //
tomwalters@123 32 // Used properly, this deletes the object when the last reference goes away.
tomwalters@123 33 // There are several caveats:
tomwalters@123 34 // - Like all reference counting schemes, cycles lead to leaks.
tomwalters@123 35 // - Each smart pointer is actually two pointers (8 bytes instead of 4).
tomwalters@123 36 // - Every time a pointer is assigned, the entire list of pointers to that
tomwalters@123 37 // object is traversed. This class is therefore NOT SUITABLE when there
tomwalters@123 38 // will often be more than two or three pointers to a particular object.
tomwalters@123 39 // - References are only tracked as long as linked_ptr<> objects are copied.
tomwalters@123 40 // If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
tomwalters@123 41 // will happen (double deletion).
tomwalters@123 42 //
tomwalters@123 43 // A good use of this class is storing object references in STL containers.
tomwalters@123 44 // You can safely put linked_ptr<> in a vector<>.
tomwalters@123 45 // Other uses may not be as good.
tomwalters@123 46 //
tomwalters@123 47 // Note: If you use an incomplete type with linked_ptr<>, the class
tomwalters@123 48 // *containing* linked_ptr<> must have a constructor and destructor (even
tomwalters@123 49 // if they do nothing!).
tomwalters@123 50 //
tomwalters@123 51 // Bill Gibbons suggested we use something like this. Yonat Sharon has
tomwalters@123 52 // a different (less useful IMHO) implementation at ootips.org.
tomwalters@123 53 //
tomwalters@123 54 // Thread Safety:
tomwalters@123 55 // A linked_ptr is NOT thread safe. Copying a linked_ptr object is
tomwalters@123 56 // effectively a read-write operation.
tomwalters@123 57
tomwalters@123 58 #ifndef UTIL_GTL_LINKED_PTR_H__
tomwalters@123 59 #define UTIL_GTL_LINKED_PTR_H__
tomwalters@123 60
tomwalters@123 61 #include <assert.h>
tomwalters@123 62
tomwalters@123 63 // This is used internally by all instances of linked_ptr<>. It needs to be
tomwalters@123 64 // a non-template class because different types of linked_ptr<> can refer to
tomwalters@123 65 // the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
tomwalters@123 66 // So, it needs to be possible for different types of linked_ptr to participate
tomwalters@123 67 // in the same circular linked list, so we need a single class type here.
tomwalters@123 68 //
tomwalters@123 69 // DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
tomwalters@123 70 class linked_ptr_internal {
tomwalters@123 71 public:
tomwalters@123 72 // Create a new circle that includes only this instance.
tomwalters@123 73 void join_new() {
tomwalters@123 74 next_ = this;
tomwalters@123 75 }
tomwalters@123 76
tomwalters@123 77 // Join an existing circle.
tomwalters@123 78 void join(linked_ptr_internal const* ptr) {
tomwalters@123 79 linked_ptr_internal const* p = ptr;
tomwalters@123 80 while (p->next_ != ptr) p = p->next_;
tomwalters@123 81 p->next_ = this;
tomwalters@123 82 next_ = ptr;
tomwalters@123 83 }
tomwalters@123 84
tomwalters@123 85 // Leave whatever circle we're part of. Returns true iff we were the
tomwalters@123 86 // last member of the circle. Once this is done, you can join() another.
tomwalters@123 87 bool depart() {
tomwalters@123 88 if (next_ == this) return true;
tomwalters@123 89 linked_ptr_internal const* p = next_;
tomwalters@123 90 while (p->next_ != this) p = p->next_;
tomwalters@123 91 p->next_ = next_;
tomwalters@123 92 return false;
tomwalters@123 93 }
tomwalters@123 94
tomwalters@123 95 private:
tomwalters@123 96 mutable linked_ptr_internal const* next_;
tomwalters@123 97 };
tomwalters@123 98
tomwalters@123 99 template <typename T>
tomwalters@123 100 class linked_ptr {
tomwalters@123 101 public:
tomwalters@123 102 typedef T element_type;
tomwalters@123 103
tomwalters@123 104 // Take over ownership of a raw pointer. This should happen as soon as
tomwalters@123 105 // possible after the object is created.
tomwalters@123 106 explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
tomwalters@123 107 ~linked_ptr() { depart(); }
tomwalters@123 108
tomwalters@123 109 // Copy an existing linked_ptr<>, adding ourselves to the list of references.
tomwalters@123 110 template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
tomwalters@123 111 linked_ptr(linked_ptr const& ptr) { assert(&ptr != this); copy(&ptr); }
tomwalters@123 112
tomwalters@123 113 // Assignment releases the old value and acquires the new.
tomwalters@123 114 template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
tomwalters@123 115 depart();
tomwalters@123 116 copy(&ptr);
tomwalters@123 117 return *this;
tomwalters@123 118 }
tomwalters@123 119
tomwalters@123 120 linked_ptr& operator=(linked_ptr const& ptr) {
tomwalters@123 121 if (&ptr != this) {
tomwalters@123 122 depart();
tomwalters@123 123 copy(&ptr);
tomwalters@123 124 }
tomwalters@123 125 return *this;
tomwalters@123 126 }
tomwalters@123 127
tomwalters@123 128 // Smart pointer members.
tomwalters@123 129 void reset(T* ptr = NULL) { depart(); capture(ptr); }
tomwalters@123 130 T* get() const { return value_; }
tomwalters@123 131 T* operator->() const { return value_; }
tomwalters@123 132 T& operator*() const { return *value_; }
tomwalters@123 133 // Release ownership of the pointed object and returns it.
tomwalters@123 134 // Sole ownership by this linked_ptr object is required.
tomwalters@123 135 T* release() {
tomwalters@123 136 // !! GOOGLE Gears specific modification !!
tomwalters@123 137 // GCC emits a warning for not using last in a opt build.
tomwalters@123 138 // Warnings are treated as errors.
tomwalters@123 139 #ifdef DEBUG
tomwalters@123 140 bool last = link_.depart();
tomwalters@123 141 assert(last);
tomwalters@123 142 #else
tomwalters@123 143 link_.depart();
tomwalters@123 144 #endif
tomwalters@123 145 T* v = value_;
tomwalters@123 146 value_ = NULL;
tomwalters@123 147 return v;
tomwalters@123 148 }
tomwalters@123 149
tomwalters@123 150 bool operator==(T* p) const { return value_ == p; }
tomwalters@123 151 bool operator!=(T* p) const { return value_ != p; }
tomwalters@123 152 template <typename U>
tomwalters@123 153 bool operator==(linked_ptr<U> const& ptr) const {
tomwalters@123 154 return value_ == ptr.get();
tomwalters@123 155 }
tomwalters@123 156 template <typename U>
tomwalters@123 157 bool operator!=(linked_ptr<U> const& ptr) const {
tomwalters@123 158 return value_ != ptr.get();
tomwalters@123 159 }
tomwalters@123 160
tomwalters@123 161 private:
tomwalters@123 162 template <typename U>
tomwalters@123 163 friend class linked_ptr;
tomwalters@123 164
tomwalters@123 165 T* value_;
tomwalters@123 166 linked_ptr_internal link_;
tomwalters@123 167
tomwalters@123 168 void depart() {
tomwalters@123 169 if (link_.depart()) delete value_;
tomwalters@123 170 }
tomwalters@123 171
tomwalters@123 172 void capture(T* ptr) {
tomwalters@123 173 value_ = ptr;
tomwalters@123 174 link_.join_new();
tomwalters@123 175 }
tomwalters@123 176
tomwalters@123 177 template <typename U> void copy(linked_ptr<U> const* ptr) {
tomwalters@123 178 value_ = ptr->get();
tomwalters@123 179 if (value_)
tomwalters@123 180 link_.join(&ptr->link_);
tomwalters@123 181 else
tomwalters@123 182 link_.join_new();
tomwalters@123 183 }
tomwalters@123 184 };
tomwalters@123 185
tomwalters@123 186 template<typename T> inline
tomwalters@123 187 bool operator==(T* ptr, const linked_ptr<T>& x) {
tomwalters@123 188 return ptr == x.get();
tomwalters@123 189 }
tomwalters@123 190
tomwalters@123 191 template<typename T> inline
tomwalters@123 192 bool operator!=(T* ptr, const linked_ptr<T>& x) {
tomwalters@123 193 return ptr != x.get();
tomwalters@123 194 }
tomwalters@123 195
tomwalters@123 196 // A function to convert T* into linked_ptr<T>
tomwalters@123 197 // Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
tomwalters@123 198 // for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
tomwalters@123 199 template <typename T>
tomwalters@123 200 linked_ptr<T> make_linked_ptr(T* ptr) {
tomwalters@123 201 return linked_ptr<T>(ptr);
tomwalters@123 202 }
tomwalters@123 203
tomwalters@123 204 #endif // UTIL_GTL_LINKED_PTR_H__