// Copyright 2019 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UTIL_WEAK_PTR_H_ #define UTIL_WEAK_PTR_H_ #include <memory> #include <utility> #include "util/osp_logging.h" namespace openscreen { // Weak pointers are pointers to an object that do not affect its lifetime, // and which may be invalidated (i.e. reset to nullptr) by the object, or its // owner, at any time; most commonly when the object is about to be deleted. // // Weak pointers are useful when an object needs to be accessed safely by one // or more objects other than its owner, and those callers can cope with the // object vanishing and e.g. tasks posted to it being silently dropped. // Reference-counting such an object would complicate the ownership graph and // make it harder to reason about the object's lifetime. // // EXAMPLE: // // class Controller { // public: // void SpawnWorker() { new Worker(weak_factory_.GetWeakPtr()); } // void WorkComplete(const Result& result) { ... } // private: // // Member variables should appear before the WeakPtrFactory, to ensure // // that any WeakPtrs to Controller are invalidated before its members // // variable's destructors are executed, rendering them invalid. // WeakPtrFactory<Controller> weak_factory_{this}; // }; // // class Worker { // public: // explicit Worker(WeakPtr<Controller> controller) // : controller_(std::move(controller)) {} // private: // void DidCompleteAsynchronousProcessing(const Result& result) { // if (controller_) // controller_->WorkComplete(result); // delete this; // } // const WeakPtr<Controller> controller_; // }; // // With this implementation a caller may use SpawnWorker() to dispatch multiple // Workers and subsequently delete the Controller, without waiting for all // Workers to have completed. // // ------------------------- IMPORTANT: Thread-safety ------------------------- // // Generally, Open Screen code is meant to be single-threaded. For the few // exceptional cases, the following is relevant: // // WeakPtrs may be created from WeakPtrFactory, and also duplicated/moved on any // thread/sequence. However, they may only be dereferenced on the same // thread/sequence that will ultimately execute the WeakPtrFactory destructor or // call InvalidateWeakPtrs(). Otherwise, use-during-free or use-after-free is // possible. // // openscreen::WeakPtr and WeakPtrFactory are similar, but not identical, to // Chromium's base::WeakPtrFactory. Open Screen WeakPtrs may be safely created // from WeakPtrFactory on any thread/sequence, since they are backed by the // thread-safe bookkeeping of std::shared_ptr<>. template <typename T> class WeakPtrFactory; template <typename T> class WeakPtr { … }; // Allow callers to compare WeakPtrs against nullptr to test validity. template <typename T> bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) { … } template <typename T> bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) { … } template <typename T> bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) { … } template <typename T> bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) { … } template <typename T> class WeakPtrFactory { … }; } // namespace openscreen #endif // UTIL_WEAK_PTR_H_