tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

UniquePtr.h (6654B)


      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 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* Smart pointer managing sole ownership of a resource. */
      8 
      9 #ifndef mozilla_UniquePtr_h
     10 #define mozilla_UniquePtr_h
     11 
     12 #include <memory>
     13 #include <utility>
     14 
     15 #include "mozilla/Attributes.h"
     16 
     17 namespace mozilla {
     18 
     19 template <typename T>
     20 using DefaultDelete = std::default_delete<T>;
     21 
     22 template <typename T, class D = DefaultDelete<T>>
     23 using UniquePtr = std::unique_ptr<T, D>;
     24 
     25 }  // namespace mozilla
     26 
     27 namespace mozilla {
     28 
     29 namespace detail {
     30 
     31 template <typename T>
     32 struct UniqueSelector {
     33  typedef UniquePtr<T> SingleObject;
     34 };
     35 
     36 template <typename T>
     37 struct UniqueSelector<T[]> {
     38  typedef UniquePtr<T[]> UnknownBound;
     39 };
     40 
     41 template <typename T, decltype(sizeof(int)) N>
     42 struct UniqueSelector<T[N]> {
     43  typedef UniquePtr<T[N]> KnownBound;
     44 };
     45 
     46 }  // namespace detail
     47 
     48 /**
     49 * MakeUnique is a helper function for allocating new'd objects and arrays,
     50 * returning a UniquePtr containing the resulting pointer.  The semantics of
     51 * MakeUnique<Type>(...) are as follows.
     52 *
     53 *   If Type is an array T[n]:
     54 *     Disallowed, deleted, no overload for you!
     55 *   If Type is an array T[]:
     56 *     MakeUnique<T[]>(size_t) is the only valid overload.  The pointer returned
     57 *     is as if by |new T[n]()|, which value-initializes each element.  (If T
     58 *     isn't a class type, this will zero each element.  If T is a class type,
     59 *     then roughly speaking, each element will be constructed using its default
     60 *     constructor.  See C++11 [dcl.init]p7 for the full gory details.)
     61 *   If Type is non-array T:
     62 *     The arguments passed to MakeUnique<T>(...) are forwarded into a
     63 *     |new T(...)| call, initializing the T as would happen if executing
     64 *     |T(...)|.
     65 *
     66 * There are various benefits to using MakeUnique instead of |new| expressions.
     67 *
     68 * First, MakeUnique eliminates use of |new| from code entirely.  If objects are
     69 * only created through UniquePtr, then (assuming all explicit release() calls
     70 * are safe, including transitively, and no type-safety casting funniness)
     71 * correctly maintained ownership of the UniquePtr guarantees no leaks are
     72 * possible.  (This pays off best if a class is only ever created through a
     73 * factory method on the class, using a private constructor.)
     74 *
     75 * Second, initializing a UniquePtr using a |new| expression requires repeating
     76 * the name of the new'd type, whereas MakeUnique in concert with the |auto|
     77 * keyword names it only once:
     78 *
     79 *   UniquePtr<char> ptr1(new char()); // repetitive
     80 *   auto ptr2 = MakeUnique<char>();   // shorter
     81 *
     82 * Of course this assumes the reader understands the operation MakeUnique
     83 * performs.  In the long run this is probably a reasonable assumption.  In the
     84 * short run you'll have to use your judgment about what readers can be expected
     85 * to know, or to quickly look up.
     86 *
     87 * Third, a call to MakeUnique can be assigned directly to a UniquePtr.  In
     88 * contrast you can't assign a pointer into a UniquePtr without using the
     89 * cumbersome reset().
     90 *
     91 *   UniquePtr<char> p;
     92 *   p = new char;           // ERROR
     93 *   p.reset(new char);      // works, but fugly
     94 *   p = MakeUnique<char>(); // preferred
     95 *
     96 * (And third, although not relevant to Mozilla: MakeUnique is exception-safe.
     97 * An exception thrown after |new T| succeeds will leak that memory, unless the
     98 * pointer is assigned to an object that will manage its ownership.  UniquePtr
     99 * ably serves this function.)
    100 */
    101 
    102 template <typename T, typename... Args>
    103 auto MakeUnique(Args&&... aArgs) {
    104  return std::make_unique<T>(std::forward<Args>(aArgs)...);
    105 }
    106 
    107 /**
    108 * WrapUnique is a helper function to transfer ownership from a raw pointer
    109 * into a UniquePtr<T>. It can only be used with a single non-array type.
    110 *
    111 * It is generally used this way:
    112 *
    113 *   auto p = WrapUnique(new char);
    114 *
    115 * It can be used when MakeUnique is not usable, for example, when the
    116 * constructor you are using is private, or you want to use aggregate
    117 * initialization.
    118 */
    119 
    120 template <typename T>
    121 typename detail::UniqueSelector<T>::SingleObject WrapUnique(T* aPtr) {
    122  return UniquePtr<T>(aPtr);
    123 }
    124 
    125 }  // namespace mozilla
    126 
    127 /**
    128 TempPtrToSetter(UniquePtr<T>*) -> T**-ish
    129 TempPtrToSetter(std::unique_ptr<T>*) -> T**-ish
    130 
    131 Make a temporary class to support assigning to UniquePtr/unique_ptr via passing
    132 a pointer to the callee.
    133 
    134 Often, APIs will be shaped like this trivial example:
    135 ```
    136 nsresult Foo::NewChildBar(Bar** out) {
    137  if (!IsOk()) return NS_ERROR_FAILURE;
    138  *out = new Bar(this);
    139  return NS_OK;
    140 }
    141 ```
    142 
    143 In order to make this work with unique ptrs, it's often either risky or
    144 overwrought:
    145 ```
    146 Bar* bar = nullptr;
    147 const auto cleanup = MakeScopeExit([&]() {
    148  if (bar) {
    149    delete bar;
    150  }
    151 });
    152 if (FAILED(foo->NewChildBar(&bar)) {
    153  // handle it
    154 }
    155 ```
    156 
    157 ```
    158 UniquePtr<Bar> bar;
    159 {
    160  Bar* raw = nullptr;
    161  const auto res = foo->NewChildBar(&bar);
    162  bar.reset(raw);
    163  if (FAILED(res) {
    164    // handle it
    165  }
    166 }
    167 ```
    168 TempPtrToSettable is a shorthand for the latter approach, allowing something
    169 cleaner but also safe:
    170 
    171 ```
    172 UniquePtr<Bar> bar;
    173 if (FAILED(foo->NewChildBar(TempPtrToSetter(&bar))) {
    174  // handle it
    175 }
    176 ```
    177 */
    178 
    179 namespace mozilla {
    180 namespace detail {
    181 
    182 template <class T, class UniquePtrT>
    183 class MOZ_TEMPORARY_CLASS TempPtrToSetterT final {
    184 private:
    185  UniquePtrT* const mDest;
    186  T* mNewVal;
    187 
    188 public:
    189  explicit TempPtrToSetterT(UniquePtrT* dest)
    190      : mDest(dest), mNewVal(mDest->get()) {}
    191 
    192  operator T**() { return &mNewVal; }
    193 
    194  ~TempPtrToSetterT() {
    195    if (mDest->get() != mNewVal) {
    196      mDest->reset(mNewVal);
    197    }
    198  }
    199 };
    200 
    201 }  // namespace detail
    202 
    203 template <class T, class Deleter>
    204 auto TempPtrToSetter(UniquePtr<T, Deleter>* const p) {
    205  return detail::TempPtrToSetterT<T, UniquePtr<T, Deleter>>{p};
    206 }
    207 
    208 }  // namespace mozilla
    209 
    210 namespace std {
    211 
    212 // No operator<, operator>, operator<=, operator>= for now because simplicity.
    213 
    214 template <typename T, class D>
    215 bool operator==(const mozilla::UniquePtr<T, D>& aX, const T* aY) {
    216  return aX.get() == aY;
    217 }
    218 
    219 template <typename T, class D>
    220 bool operator==(const T* aY, const mozilla::UniquePtr<T, D>& aX) {
    221  return aY == aX.get();
    222 }
    223 
    224 template <typename T, class D>
    225 bool operator!=(const mozilla::UniquePtr<T, D>& aX, const T* aY) {
    226  return aX.get() != aY;
    227 }
    228 
    229 template <typename T, class D>
    230 bool operator!=(const T* aY, const mozilla::UniquePtr<T, D>& aX) {
    231  return aY != aX.get();
    232 }
    233 }  // namespace std
    234 
    235 #endif /* mozilla_UniquePtr_h */