1 // Copyright 2023 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // ----------------------------------------------------------------------------- 16 // File: no_destructor.h 17 // ----------------------------------------------------------------------------- 18 // 19 // This header file defines the absl::NoDestructor<T> wrapper for defining a 20 // static type that does not need to be destructed upon program exit. Instead, 21 // such an object survives during program exit (and can be safely accessed at 22 // any time). 23 // 24 // Objects of such type, if constructed safely and under the right conditions, 25 // provide two main benefits over other alternatives: 26 // 27 // * Global objects not normally allowed due to concerns of destruction order 28 // (i.e. no "complex globals") can be safely allowed, provided that such 29 // objects can be constant initialized. 30 // * Function scope static objects can be optimized to avoid heap allocation, 31 // pointer chasing, and allow lazy construction. 32 // 33 // See below for complete details. 34 35 36 #ifndef ABSL_BASE_NO_DESTRUCTOR_H_ 37 #define ABSL_BASE_NO_DESTRUCTOR_H_ 38 39 #include <new> 40 #include <type_traits> 41 #include <utility> 42 43 #include "absl/base/config.h" 44 45 namespace absl { 46 ABSL_NAMESPACE_BEGIN 47 48 // absl::NoDestructor<T> 49 // 50 // NoDestructor<T> is a wrapper around an object of type T that behaves as an 51 // object of type T but never calls T's destructor. NoDestructor<T> makes it 52 // safer and/or more efficient to use such objects in static storage contexts: 53 // as global or function scope static variables. 54 // 55 // An instance of absl::NoDestructor<T> has similar type semantics to an 56 // instance of T: 57 // 58 // * Constructs in the same manner as an object of type T through perfect 59 // forwarding. 60 // * Provides pointer/reference semantic access to the object of type T via 61 // `->`, `*`, and `get()`. 62 // (Note that `const NoDestructor<T>` works like a pointer to const `T`.) 63 // 64 // An object of type NoDestructor<T> should be defined in static storage: 65 // as either a global static object, or as a function scope static variable. 66 // 67 // Additionally, NoDestructor<T> provides the following benefits: 68 // 69 // * Never calls T's destructor for the object 70 // * If the object is a function-local static variable, the type can be 71 // lazily constructed. 72 // 73 // An object of type NoDestructor<T> is "trivially destructible" in the notion 74 // that its destructor is never run. Provided that an object of this type can be 75 // safely initialized and does not need to be cleaned up on program shutdown, 76 // NoDestructor<T> allows you to define global static variables, since Google's 77 // C++ style guide ban on such objects doesn't apply to objects that are 78 // trivially destructible. 79 // 80 // Usage as Global Static Variables 81 // 82 // NoDestructor<T> allows declaration of a global object with a non-trivial 83 // constructor in static storage without needing to add a destructor. 84 // However, such objects still need to worry about initialization order, so 85 // such objects should be const initialized: 86 // 87 // // Global or namespace scope. 88 // ABSL_CONST_INIT absl::NoDestructor<MyRegistry> reg{"foo", "bar", 8008}; 89 // 90 // Note that if your object already has a trivial destructor, you don't need to 91 // use NoDestructor<T>. 92 // 93 // Usage as Function Scope Static Variables 94 // 95 // Function static objects will be lazily initialized within static storage: 96 // 97 // // Function scope. 98 // const std::string& MyString() { 99 // static const absl::NoDestructor<std::string> x("foo"); 100 // return *x; 101 // } 102 // 103 // For function static variables, NoDestructor avoids heap allocation and can be 104 // inlined in static storage, resulting in exactly-once, thread-safe 105 // construction of an object, and very fast access thereafter (the cost is a few 106 // extra cycles). 107 // 108 // Using NoDestructor<T> in this manner is generally better than other patterns 109 // which require pointer chasing: 110 // 111 // // Prefer using absl::NoDestructor<T> instead for the static variable. 112 // const std::string& MyString() { 113 // static const std::string* x = new std::string("foo"); 114 // return *x; 115 // } 116 // 117 template <typename T> 118 class NoDestructor { 119 public: 120 // Forwards arguments to the T's constructor: calls T(args...). 121 template <typename... Ts, 122 // Disable this overload when it might collide with copy/move. 123 typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...), 124 void(NoDestructor&)>::value, 125 int>::type = 0> NoDestructor(Ts &&...args)126 explicit constexpr NoDestructor(Ts&&... args) 127 : impl_(std::forward<Ts>(args)...) {} 128 129 // Forwards copy and move construction for T. Enables usage like this: 130 // static NoDestructor<std::array<string, 3>> x{{{"1", "2", "3"}}}; 131 // static NoDestructor<std::vector<int>> x{{1, 2, 3}}; NoDestructor(const T & x)132 explicit constexpr NoDestructor(const T& x) : impl_(x) {} NoDestructor(T && x)133 explicit constexpr NoDestructor(T&& x) 134 : impl_(std::move(x)) {} 135 136 // No copying. 137 NoDestructor(const NoDestructor&) = delete; 138 NoDestructor& operator=(const NoDestructor&) = delete; 139 140 // Pretend to be a smart pointer to T with deep constness. 141 // Never returns a null pointer. 142 T& operator*() { return *get(); } 143 T* operator->() { return get(); } get()144 T* get() { return impl_.get(); } 145 const T& operator*() const { return *get(); } 146 const T* operator->() const { return get(); } get()147 const T* get() const { return impl_.get(); } 148 149 private: 150 class DirectImpl { 151 public: 152 template <typename... Args> DirectImpl(Args &&...args)153 explicit constexpr DirectImpl(Args&&... args) 154 : value_(std::forward<Args>(args)...) {} get()155 const T* get() const { return &value_; } get()156 T* get() { return &value_; } 157 158 private: 159 T value_; 160 }; 161 162 class PlacementImpl { 163 public: 164 template <typename... Args> PlacementImpl(Args &&...args)165 explicit PlacementImpl(Args&&... args) { 166 new (&space_) T(std::forward<Args>(args)...); 167 } get()168 const T* get() const { 169 return Launder(reinterpret_cast<const T*>(&space_)); 170 } get()171 T* get() { return Launder(reinterpret_cast<T*>(&space_)); } 172 173 private: 174 template <typename P> Launder(P * p)175 static P* Launder(P* p) { 176 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L 177 return std::launder(p); 178 #elif ABSL_HAVE_BUILTIN(__builtin_launder) 179 return __builtin_launder(p); 180 #else 181 // When `std::launder` or equivalent are not available, we rely on 182 // undefined behavior, which works as intended on Abseil's officially 183 // supported platforms as of Q3 2023. 184 #if defined(__GNUC__) && !defined(__clang__) 185 #pragma GCC diagnostic push 186 #pragma GCC diagnostic ignored "-Wstrict-aliasing" 187 #endif 188 return p; 189 #if defined(__GNUC__) && !defined(__clang__) 190 #pragma GCC diagnostic pop 191 #endif 192 #endif 193 } 194 195 alignas(T) unsigned char space_[sizeof(T)]; 196 }; 197 198 // If the object is trivially destructible we use a member directly to avoid 199 // potential once-init runtime initialization. It somewhat defeats the 200 // purpose of NoDestructor in this case, but this makes the class more 201 // friendly to generic code. 202 std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl, 203 PlacementImpl> 204 impl_; 205 }; 206 207 #ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 208 // Provide 'Class Template Argument Deduction': the type of NoDestructor's T 209 // will be the same type as the argument passed to NoDestructor's constructor. 210 template <typename T> 211 NoDestructor(T) -> NoDestructor<T>; 212 #endif // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 213 214 ABSL_NAMESPACE_END 215 } // namespace absl 216 217 #endif // ABSL_BASE_NO_DESTRUCTOR_H_ 218