// Copyright 2014 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_SCOPED_GENERIC_H_ #define BASE_SCOPED_GENERIC_H_ #include <stdlib.h> #include <concepts> #include <type_traits> #include "base/check.h" #include "base/memory/raw_ptr.h" namespace base { // This class acts like unique_ptr with a custom deleter (although is slightly // less fancy in some of the more escoteric respects) except that it keeps a // copy of the object rather than a pointer, and we require that the contained // object has some kind of "invalid" value. // // Defining a scoper based on this class allows you to get a scoper for // non-pointer types without having to write custom code for set, reset, and // move, etc. and get almost identical semantics that people are used to from // unique_ptr. // // It is intended that you will typedef this class with an appropriate deleter // to implement clean up tasks for objects that act like pointers from a // resource management standpoint but aren't, such as file descriptors and // various types of operating system handles. Using unique_ptr for these // things requires that you keep a pointer to the handle valid for the lifetime // of the scoper (which is easy to mess up). // // For an object to be able to be put into a ScopedGeneric, it must support // standard copyable semantics and have a specific "invalid" value. The traits // must define a free function and also the invalid value to assign for // default-constructed and released objects. // // struct FooScopedTraits { // // It's assumed that this is a fast inline function with little-to-no // // penalty for duplicate calls. This must be a static function even // // for stateful traits. // static int InvalidValue() { // return 0; // } // // // This free function will not be called if f == InvalidValue()! // static void Free(int f) { // ::FreeFoo(f); // } // }; // // using ScopedFoo = ScopedGeneric<int, FooScopedTraits>; // // A Traits type may choose to track ownership of objects in parallel with // ScopedGeneric. To do so, it must implement the Acquire and Release methods, // which will be called by ScopedGeneric during ownership transfers and extend // the ScopedGenericOwnershipTracking tag type. // // struct BarScopedTraits : public ScopedGenericOwnershipTracking { // using ScopedGenericType = ScopedGeneric<int, BarScopedTraits>; // static int InvalidValue() { // return 0; // } // // static void Free(int b) { // ::FreeBar(b); // } // // static void Acquire(const ScopedGenericType& owner, int b) { // ::TrackAcquisition(b, owner); // } // // static void Release(const ScopedGenericType& owner, int b) { // ::TrackRelease(b, owner); // } // }; // // using ScopedBar = ScopedGeneric<int, BarScopedTraits>; struct ScopedGenericOwnershipTracking { … }; template<typename T, typename Traits> class ScopedGeneric { … }; template<class T, class Traits> void swap(const ScopedGeneric<T, Traits>& a, const ScopedGeneric<T, Traits>& b) { … } template<class T, class Traits> bool operator==(const T& value, const ScopedGeneric<T, Traits>& scoped) { … } template<class T, class Traits> bool operator!=(const T& value, const ScopedGeneric<T, Traits>& scoped) { … } } // namespace base #endif // BASE_SCOPED_GENERIC_H_