linked_ptr.h (5638B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 // 7 // A "smart" pointer type with reference tracking. Every pointer to a 8 // particular object is kept on a circular linked list. When the last pointer 9 // to an object is destroyed or reassigned, the object is deleted. 10 // 11 // Used properly, this deletes the object when the last reference goes away. 12 // There are several caveats: 13 // - Like all reference counting schemes, cycles lead to leaks. 14 // - Each smart pointer is actually two pointers (8 bytes instead of 4). 15 // - Every time a pointer is released, the entire list of pointers to that 16 // object is traversed. This class is therefore NOT SUITABLE when there 17 // will often be more than two or three pointers to a particular object. 18 // - References are only tracked as long as linked_ptr<> objects are copied. 19 // If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS 20 // will happen (double deletion). 21 // 22 // A good use of this class is storing object references in STL containers. 23 // You can safely put linked_ptr<> in a vector<>. 24 // Other uses may not be as good. 25 // 26 // Note: If you use an incomplete type with linked_ptr<>, the class 27 // *containing* linked_ptr<> must have a constructor and destructor (even 28 // if they do nothing!). 29 // 30 // Thread Safety: 31 // A linked_ptr is NOT thread safe. Copying a linked_ptr object is 32 // effectively a read-write operation. 33 // 34 // Alternative: to linked_ptr is shared_ptr, which 35 // - is also two pointers in size (8 bytes for 32 bit addresses) 36 // - is thread safe for copying and deletion 37 // - supports weak_ptrs 38 39 #ifndef BASE_LINKED_PTR_H_ 40 #define BASE_LINKED_PTR_H_ 41 42 #include "base/logging.h" // for CHECK macros 43 44 // This is used internally by all instances of linked_ptr<>. It needs to be 45 // a non-template class because different types of linked_ptr<> can refer to 46 // the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)). 47 // So, it needs to be possible for different types of linked_ptr to participate 48 // in the same circular linked list, so we need a single class type here. 49 // 50 // DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>. 51 class linked_ptr_internal { 52 public: 53 // Create a new circle that includes only this instance. 54 void join_new() { next_ = this; } 55 56 // Join an existing circle. 57 void join(linked_ptr_internal const* ptr) { 58 next_ = ptr->next_; 59 ptr->next_ = this; 60 } 61 62 // Leave whatever circle we're part of. Returns true iff we were the 63 // last member of the circle. Once this is done, you can join() another. 64 bool depart() { 65 if (next_ == this) return true; 66 linked_ptr_internal const* p = next_; 67 while (p->next_ != this) p = p->next_; 68 p->next_ = next_; 69 return false; 70 } 71 72 private: 73 mutable linked_ptr_internal const* next_; 74 }; 75 76 template <typename T> 77 class linked_ptr { 78 public: 79 typedef T element_type; 80 81 // Take over ownership of a raw pointer. This should happen as soon as 82 // possible after the object is created. 83 explicit linked_ptr(T* ptr = NULL) { capture(ptr); } 84 ~linked_ptr() { depart(); } 85 86 // Copy an existing linked_ptr<>, adding ourselves to the list of references. 87 template <typename U> 88 linked_ptr(linked_ptr<U> const& ptr) { 89 copy(&ptr); 90 } 91 linked_ptr(linked_ptr const& ptr) { 92 DCHECK_NE(&ptr, this); 93 copy(&ptr); 94 } 95 96 // Assignment releases the old value and acquires the new. 97 template <typename U> 98 linked_ptr& operator=(linked_ptr<U> const& ptr) { 99 depart(); 100 copy(&ptr); 101 return *this; 102 } 103 104 linked_ptr& operator=(linked_ptr const& ptr) { 105 if (&ptr != this) { 106 depart(); 107 copy(&ptr); 108 } 109 return *this; 110 } 111 112 // Smart pointer members. 113 void reset(T* ptr = NULL) { 114 depart(); 115 capture(ptr); 116 } 117 T* get() const { return value_; } 118 T* operator->() const { return value_; } 119 T& operator*() const { return *value_; } 120 // Release ownership of the pointed object and returns it. 121 // Sole ownership by this linked_ptr object is required. 122 T* release() { 123 bool last = link_.depart(); 124 CHECK(last); 125 T* v = value_; 126 value_ = NULL; 127 return v; 128 } 129 130 bool operator==(const T* p) const { return value_ == p; } 131 bool operator!=(const T* p) const { return value_ != p; } 132 template <typename U> 133 bool operator==(linked_ptr<U> const& ptr) const { 134 return value_ == ptr.get(); 135 } 136 template <typename U> 137 bool operator!=(linked_ptr<U> const& ptr) const { 138 return value_ != ptr.get(); 139 } 140 141 private: 142 template <typename U> 143 friend class linked_ptr; 144 145 T* value_; 146 linked_ptr_internal link_; 147 148 void depart() { 149 if (link_.depart()) delete value_; 150 } 151 152 void capture(T* ptr) { 153 value_ = ptr; 154 link_.join_new(); 155 } 156 157 template <typename U> 158 void copy(linked_ptr<U> const* ptr) { 159 value_ = ptr->get(); 160 if (value_) 161 link_.join(&ptr->link_); 162 else 163 link_.join_new(); 164 } 165 }; 166 167 template <typename T> 168 inline bool operator==(T* ptr, const linked_ptr<T>& x) { 169 return ptr == x.get(); 170 } 171 172 template <typename T> 173 inline bool operator!=(T* ptr, const linked_ptr<T>& x) { 174 return ptr != x.get(); 175 } 176 177 // A function to convert T* into linked_ptr<T> 178 // Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation 179 // for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg)) 180 template <typename T> 181 linked_ptr<T> make_linked_ptr(T* ptr) { 182 return linked_ptr<T>(ptr); 183 } 184 185 #endif // BASE_LINKED_PTR_H_