1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved. 2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be 3*3f982cf4SFabien Sanglard // found in the LICENSE file. 4*3f982cf4SFabien Sanglard 5*3f982cf4SFabien Sanglard #ifndef UTIL_WEAK_PTR_H_ 6*3f982cf4SFabien Sanglard #define UTIL_WEAK_PTR_H_ 7*3f982cf4SFabien Sanglard 8*3f982cf4SFabien Sanglard #include <memory> 9*3f982cf4SFabien Sanglard #include <utility> 10*3f982cf4SFabien Sanglard 11*3f982cf4SFabien Sanglard #include "util/osp_logging.h" 12*3f982cf4SFabien Sanglard 13*3f982cf4SFabien Sanglard namespace openscreen { 14*3f982cf4SFabien Sanglard 15*3f982cf4SFabien Sanglard // Weak pointers are pointers to an object that do not affect its lifetime, 16*3f982cf4SFabien Sanglard // and which may be invalidated (i.e. reset to nullptr) by the object, or its 17*3f982cf4SFabien Sanglard // owner, at any time; most commonly when the object is about to be deleted. 18*3f982cf4SFabien Sanglard // 19*3f982cf4SFabien Sanglard // Weak pointers are useful when an object needs to be accessed safely by one 20*3f982cf4SFabien Sanglard // or more objects other than its owner, and those callers can cope with the 21*3f982cf4SFabien Sanglard // object vanishing and e.g. tasks posted to it being silently dropped. 22*3f982cf4SFabien Sanglard // Reference-counting such an object would complicate the ownership graph and 23*3f982cf4SFabien Sanglard // make it harder to reason about the object's lifetime. 24*3f982cf4SFabien Sanglard // 25*3f982cf4SFabien Sanglard // EXAMPLE: 26*3f982cf4SFabien Sanglard // 27*3f982cf4SFabien Sanglard // class Controller { 28*3f982cf4SFabien Sanglard // public: 29*3f982cf4SFabien Sanglard // void SpawnWorker() { new Worker(weak_factory_.GetWeakPtr()); } 30*3f982cf4SFabien Sanglard // void WorkComplete(const Result& result) { ... } 31*3f982cf4SFabien Sanglard // private: 32*3f982cf4SFabien Sanglard // // Member variables should appear before the WeakPtrFactory, to ensure 33*3f982cf4SFabien Sanglard // // that any WeakPtrs to Controller are invalidated before its members 34*3f982cf4SFabien Sanglard // // variable's destructors are executed, rendering them invalid. 35*3f982cf4SFabien Sanglard // WeakPtrFactory<Controller> weak_factory_{this}; 36*3f982cf4SFabien Sanglard // }; 37*3f982cf4SFabien Sanglard // 38*3f982cf4SFabien Sanglard // class Worker { 39*3f982cf4SFabien Sanglard // public: 40*3f982cf4SFabien Sanglard // explicit Worker(WeakPtr<Controller> controller) 41*3f982cf4SFabien Sanglard // : controller_(std::move(controller)) {} 42*3f982cf4SFabien Sanglard // private: 43*3f982cf4SFabien Sanglard // void DidCompleteAsynchronousProcessing(const Result& result) { 44*3f982cf4SFabien Sanglard // if (controller_) 45*3f982cf4SFabien Sanglard // controller_->WorkComplete(result); 46*3f982cf4SFabien Sanglard // delete this; 47*3f982cf4SFabien Sanglard // } 48*3f982cf4SFabien Sanglard // const WeakPtr<Controller> controller_; 49*3f982cf4SFabien Sanglard // }; 50*3f982cf4SFabien Sanglard // 51*3f982cf4SFabien Sanglard // With this implementation a caller may use SpawnWorker() to dispatch multiple 52*3f982cf4SFabien Sanglard // Workers and subsequently delete the Controller, without waiting for all 53*3f982cf4SFabien Sanglard // Workers to have completed. 54*3f982cf4SFabien Sanglard // 55*3f982cf4SFabien Sanglard // ------------------------- IMPORTANT: Thread-safety ------------------------- 56*3f982cf4SFabien Sanglard // 57*3f982cf4SFabien Sanglard // Generally, Open Screen code is meant to be single-threaded. For the few 58*3f982cf4SFabien Sanglard // exceptional cases, the following is relevant: 59*3f982cf4SFabien Sanglard // 60*3f982cf4SFabien Sanglard // WeakPtrs may be created from WeakPtrFactory, and also duplicated/moved on any 61*3f982cf4SFabien Sanglard // thread/sequence. However, they may only be dereferenced on the same 62*3f982cf4SFabien Sanglard // thread/sequence that will ultimately execute the WeakPtrFactory destructor or 63*3f982cf4SFabien Sanglard // call InvalidateWeakPtrs(). Otherwise, use-during-free or use-after-free is 64*3f982cf4SFabien Sanglard // possible. 65*3f982cf4SFabien Sanglard // 66*3f982cf4SFabien Sanglard // openscreen::WeakPtr and WeakPtrFactory are similar, but not identical, to 67*3f982cf4SFabien Sanglard // Chromium's base::WeakPtrFactory. Open Screen WeakPtrs may be safely created 68*3f982cf4SFabien Sanglard // from WeakPtrFactory on any thread/sequence, since they are backed by the 69*3f982cf4SFabien Sanglard // thread-safe bookkeeping of std::shared_ptr<>. 70*3f982cf4SFabien Sanglard 71*3f982cf4SFabien Sanglard template <typename T> 72*3f982cf4SFabien Sanglard class WeakPtrFactory; 73*3f982cf4SFabien Sanglard 74*3f982cf4SFabien Sanglard template <typename T> 75*3f982cf4SFabien Sanglard class WeakPtr { 76*3f982cf4SFabien Sanglard public: 77*3f982cf4SFabien Sanglard WeakPtr() = default; 78*3f982cf4SFabien Sanglard ~WeakPtr() = default; 79*3f982cf4SFabien Sanglard 80*3f982cf4SFabien Sanglard // Copy/Move constructors and assignment operators. WeakPtr(const WeakPtr & other)81*3f982cf4SFabien Sanglard WeakPtr(const WeakPtr& other) : impl_(other.impl_) {} 82*3f982cf4SFabien Sanglard WeakPtr(WeakPtr && other)83*3f982cf4SFabien Sanglard WeakPtr(WeakPtr&& other) noexcept : impl_(std::move(other.impl_)) {} 84*3f982cf4SFabien Sanglard 85*3f982cf4SFabien Sanglard WeakPtr& operator=(const WeakPtr& other) { 86*3f982cf4SFabien Sanglard impl_ = other.impl_; 87*3f982cf4SFabien Sanglard return *this; 88*3f982cf4SFabien Sanglard } 89*3f982cf4SFabien Sanglard 90*3f982cf4SFabien Sanglard WeakPtr& operator=(WeakPtr&& other) noexcept { 91*3f982cf4SFabien Sanglard impl_ = std::move(other.impl_); 92*3f982cf4SFabien Sanglard return *this; 93*3f982cf4SFabien Sanglard } 94*3f982cf4SFabien Sanglard 95*3f982cf4SFabien Sanglard // Create/Assign from nullptr. WeakPtr(std::nullptr_t)96*3f982cf4SFabien Sanglard WeakPtr(std::nullptr_t) {} // NOLINT 97*3f982cf4SFabien Sanglard 98*3f982cf4SFabien Sanglard WeakPtr& operator=(std::nullptr_t) { 99*3f982cf4SFabien Sanglard impl_.reset(); 100*3f982cf4SFabien Sanglard return *this; 101*3f982cf4SFabien Sanglard } 102*3f982cf4SFabien Sanglard 103*3f982cf4SFabien Sanglard // Copy/Move constructors and assignment operators with upcast conversion. 104*3f982cf4SFabien Sanglard template <typename U> WeakPtr(const WeakPtr<U> & other)105*3f982cf4SFabien Sanglard WeakPtr(const WeakPtr<U>& other) : impl_(other.as_std_weak_ptr()) {} 106*3f982cf4SFabien Sanglard 107*3f982cf4SFabien Sanglard template <typename U> WeakPtr(WeakPtr<U> && other)108*3f982cf4SFabien Sanglard WeakPtr(WeakPtr<U>&& other) noexcept 109*3f982cf4SFabien Sanglard : impl_(std::move(other).as_std_weak_ptr()) {} 110*3f982cf4SFabien Sanglard 111*3f982cf4SFabien Sanglard template <typename U> 112*3f982cf4SFabien Sanglard WeakPtr& operator=(const WeakPtr<U>& other) { 113*3f982cf4SFabien Sanglard impl_ = other.as_std_weak_ptr(); 114*3f982cf4SFabien Sanglard return *this; 115*3f982cf4SFabien Sanglard } 116*3f982cf4SFabien Sanglard 117*3f982cf4SFabien Sanglard template <typename U> 118*3f982cf4SFabien Sanglard WeakPtr& operator=(WeakPtr<U>&& other) noexcept { 119*3f982cf4SFabien Sanglard impl_ = std::move(other).as_std_weak_ptr(); 120*3f982cf4SFabien Sanglard return *this; 121*3f982cf4SFabien Sanglard } 122*3f982cf4SFabien Sanglard 123*3f982cf4SFabien Sanglard // Accessors. get()124*3f982cf4SFabien Sanglard T* get() const { return impl_.lock().get(); } 125*3f982cf4SFabien Sanglard 126*3f982cf4SFabien Sanglard T& operator*() const { 127*3f982cf4SFabien Sanglard T* const pointer = get(); 128*3f982cf4SFabien Sanglard OSP_DCHECK(pointer); 129*3f982cf4SFabien Sanglard return *pointer; 130*3f982cf4SFabien Sanglard } 131*3f982cf4SFabien Sanglard 132*3f982cf4SFabien Sanglard T* operator->() const { 133*3f982cf4SFabien Sanglard T* const pointer = get(); 134*3f982cf4SFabien Sanglard OSP_DCHECK(pointer); 135*3f982cf4SFabien Sanglard return pointer; 136*3f982cf4SFabien Sanglard } 137*3f982cf4SFabien Sanglard 138*3f982cf4SFabien Sanglard // Allow conditionals to test validity, e.g. if (weak_ptr) {...} 139*3f982cf4SFabien Sanglard explicit operator bool() const { return get() != nullptr; } 140*3f982cf4SFabien Sanglard 141*3f982cf4SFabien Sanglard // Conversion to std::weak_ptr<T>. It is unsafe to convert in the other 142*3f982cf4SFabien Sanglard // direction. See comments for private constructors, below. as_std_weak_ptr()143*3f982cf4SFabien Sanglard const std::weak_ptr<T>& as_std_weak_ptr() const& { return impl_; } as_std_weak_ptr()144*3f982cf4SFabien Sanglard std::weak_ptr<T> as_std_weak_ptr() && { return std::move(impl_); } 145*3f982cf4SFabien Sanglard 146*3f982cf4SFabien Sanglard private: 147*3f982cf4SFabien Sanglard friend class WeakPtrFactory<T>; 148*3f982cf4SFabien Sanglard 149*3f982cf4SFabien Sanglard // Called by WeakPtrFactory<T> and the WeakPtr<T> upcast conversion 150*3f982cf4SFabien Sanglard // constructors and assigners. These are purposely not being exposed publicly 151*3f982cf4SFabien Sanglard // because that would allow a WeakPtr<T> to be valid/invalid by a different 152*3f982cf4SFabien Sanglard // ownership/threading model than the intended one (see top-level comments). 153*3f982cf4SFabien Sanglard template <typename U> WeakPtr(const std::weak_ptr<U> & other)154*3f982cf4SFabien Sanglard explicit WeakPtr(const std::weak_ptr<U>& other) : impl_(other) {} 155*3f982cf4SFabien Sanglard 156*3f982cf4SFabien Sanglard template <typename U> WeakPtr(std::weak_ptr<U> && other)157*3f982cf4SFabien Sanglard explicit WeakPtr(std::weak_ptr<U>&& other) noexcept 158*3f982cf4SFabien Sanglard : impl_(std::move(other)) {} 159*3f982cf4SFabien Sanglard 160*3f982cf4SFabien Sanglard std::weak_ptr<T> impl_; 161*3f982cf4SFabien Sanglard }; 162*3f982cf4SFabien Sanglard 163*3f982cf4SFabien Sanglard // Allow callers to compare WeakPtrs against nullptr to test validity. 164*3f982cf4SFabien Sanglard template <typename T> 165*3f982cf4SFabien Sanglard bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) { 166*3f982cf4SFabien Sanglard return weak_ptr.get() != nullptr; 167*3f982cf4SFabien Sanglard } 168*3f982cf4SFabien Sanglard template <typename T> 169*3f982cf4SFabien Sanglard bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) { 170*3f982cf4SFabien Sanglard return weak_ptr.get() != nullptr; 171*3f982cf4SFabien Sanglard } 172*3f982cf4SFabien Sanglard template <typename T> 173*3f982cf4SFabien Sanglard bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) { 174*3f982cf4SFabien Sanglard return weak_ptr.get() == nullptr; 175*3f982cf4SFabien Sanglard } 176*3f982cf4SFabien Sanglard template <typename T> 177*3f982cf4SFabien Sanglard bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) { 178*3f982cf4SFabien Sanglard return weak_ptr == nullptr; 179*3f982cf4SFabien Sanglard } 180*3f982cf4SFabien Sanglard 181*3f982cf4SFabien Sanglard template <typename T> 182*3f982cf4SFabien Sanglard class WeakPtrFactory { 183*3f982cf4SFabien Sanglard public: WeakPtrFactory(T * instance)184*3f982cf4SFabien Sanglard explicit WeakPtrFactory(T* instance) { Reset(instance); } 185*3f982cf4SFabien Sanglard WeakPtrFactory(WeakPtrFactory&& other) noexcept = default; 186*3f982cf4SFabien Sanglard WeakPtrFactory& operator=(WeakPtrFactory&& other) noexcept = default; 187*3f982cf4SFabien Sanglard 188*3f982cf4SFabien Sanglard // Thread-safe: WeakPtrs may be created on any thread/seuence. They may also 189*3f982cf4SFabien Sanglard // be copied and moved on any thread/sequence. However, they MUST only be 190*3f982cf4SFabien Sanglard // dereferenced on the same thread/sequence that calls the destructor or 191*3f982cf4SFabien Sanglard // InvalidateWeakPtrs(). GetWeakPtr()192*3f982cf4SFabien Sanglard WeakPtr<T> GetWeakPtr() const { 193*3f982cf4SFabien Sanglard return WeakPtr<T>(std::weak_ptr<T>(bookkeeper_)); 194*3f982cf4SFabien Sanglard } 195*3f982cf4SFabien Sanglard 196*3f982cf4SFabien Sanglard // Destruction and Invalidation: These must be called on the same 197*3f982cf4SFabien Sanglard // thread/sequence that dereferences any WeakPtrs to avoid use-after-free 198*3f982cf4SFabien Sanglard // bugs. 199*3f982cf4SFabien Sanglard ~WeakPtrFactory() = default; InvalidateWeakPtrs()200*3f982cf4SFabien Sanglard void InvalidateWeakPtrs() { Reset(bookkeeper_.get()); } 201*3f982cf4SFabien Sanglard 202*3f982cf4SFabien Sanglard private: 203*3f982cf4SFabien Sanglard WeakPtrFactory(const WeakPtrFactory& other) = delete; 204*3f982cf4SFabien Sanglard WeakPtrFactory& operator=(const WeakPtrFactory& other) = delete; 205*3f982cf4SFabien Sanglard Reset(T * instance)206*3f982cf4SFabien Sanglard void Reset(T* instance) { 207*3f982cf4SFabien Sanglard // T is owned externally to WeakPtrFactory. Thus, provide a no-op Deleter. 208*3f982cf4SFabien Sanglard bookkeeper_ = {instance, [](T* instance) {}}; 209*3f982cf4SFabien Sanglard } 210*3f982cf4SFabien Sanglard 211*3f982cf4SFabien Sanglard // Manages the std::weak_ptr's referring to T. Does not own T. 212*3f982cf4SFabien Sanglard std::shared_ptr<T> bookkeeper_; 213*3f982cf4SFabien Sanglard }; 214*3f982cf4SFabien Sanglard 215*3f982cf4SFabien Sanglard } // namespace openscreen 216*3f982cf4SFabien Sanglard 217*3f982cf4SFabien Sanglard #endif // UTIL_WEAK_PTR_H_ 218