|
||||
File indexing completed on 2024-11-15 09:00:52
0001 // Copyright 2023 The Abseil Authors. 0002 // 0003 // Licensed under the Apache License, Version 2.0 (the "License"); 0004 // you may not use this file except in compliance with the License. 0005 // You may obtain a copy of the License at 0006 // 0007 // https://www.apache.org/licenses/LICENSE-2.0 0008 // 0009 // Unless required by applicable law or agreed to in writing, software 0010 // distributed under the License is distributed on an "AS IS" BASIS, 0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0012 // See the License for the specific language governing permissions and 0013 // limitations under the License. 0014 // 0015 // ----------------------------------------------------------------------------- 0016 // File: no_destructor.h 0017 // ----------------------------------------------------------------------------- 0018 // 0019 // This header file defines the absl::NoDestructor<T> wrapper for defining a 0020 // static type that does not need to be destructed upon program exit. Instead, 0021 // such an object survives during program exit (and can be safely accessed at 0022 // any time). 0023 // 0024 // Objects of such type, if constructed safely and under the right conditions, 0025 // provide two main benefits over other alternatives: 0026 // 0027 // * Global objects not normally allowed due to concerns of destruction order 0028 // (i.e. no "complex globals") can be safely allowed, provided that such 0029 // objects can be constant initialized. 0030 // * Function scope static objects can be optimized to avoid heap allocation, 0031 // pointer chasing, and allow lazy construction. 0032 // 0033 // See below for complete details. 0034 0035 0036 #ifndef ABSL_BASE_NO_DESTRUCTOR_H_ 0037 #define ABSL_BASE_NO_DESTRUCTOR_H_ 0038 0039 #include <new> 0040 #include <type_traits> 0041 #include <utility> 0042 0043 #include "absl/base/config.h" 0044 0045 namespace absl { 0046 ABSL_NAMESPACE_BEGIN 0047 0048 // absl::NoDestructor<T> 0049 // 0050 // NoDestructor<T> is a wrapper around an object of type T that behaves as an 0051 // object of type T but never calls T's destructor. NoDestructor<T> makes it 0052 // safer and/or more efficient to use such objects in static storage contexts: 0053 // as global or function scope static variables. 0054 // 0055 // An instance of absl::NoDestructor<T> has similar type semantics to an 0056 // instance of T: 0057 // 0058 // * Constructs in the same manner as an object of type T through perfect 0059 // forwarding. 0060 // * Provides pointer/reference semantic access to the object of type T via 0061 // `->`, `*`, and `get()`. 0062 // (Note that `const NoDestructor<T>` works like a pointer to const `T`.) 0063 // 0064 // An object of type NoDestructor<T> should be defined in static storage: 0065 // as either a global static object, or as a function scope static variable. 0066 // 0067 // Additionally, NoDestructor<T> provides the following benefits: 0068 // 0069 // * Never calls T's destructor for the object 0070 // * If the object is a function-local static variable, the type can be 0071 // lazily constructed. 0072 // 0073 // An object of type NoDestructor<T> is "trivially destructible" in the notion 0074 // that its destructor is never run. Provided that an object of this type can be 0075 // safely initialized and does not need to be cleaned up on program shutdown, 0076 // NoDestructor<T> allows you to define global static variables, since Google's 0077 // C++ style guide ban on such objects doesn't apply to objects that are 0078 // trivially destructible. 0079 // 0080 // Usage as Global Static Variables 0081 // 0082 // NoDestructor<T> allows declaration of a global object with a non-trivial 0083 // constructor in static storage without needing to add a destructor. 0084 // However, such objects still need to worry about initialization order, so 0085 // such objects should be const initialized: 0086 // 0087 // // Global or namespace scope. 0088 // ABSL_CONST_INIT absl::NoDestructor<MyRegistry> reg{"foo", "bar", 8008}; 0089 // 0090 // Note that if your object already has a trivial destructor, you don't need to 0091 // use NoDestructor<T>. 0092 // 0093 // Usage as Function Scope Static Variables 0094 // 0095 // Function static objects will be lazily initialized within static storage: 0096 // 0097 // // Function scope. 0098 // const std::string& MyString() { 0099 // static const absl::NoDestructor<std::string> x("foo"); 0100 // return *x; 0101 // } 0102 // 0103 // For function static variables, NoDestructor avoids heap allocation and can be 0104 // inlined in static storage, resulting in exactly-once, thread-safe 0105 // construction of an object, and very fast access thereafter (the cost is a few 0106 // extra cycles). 0107 // 0108 // Using NoDestructor<T> in this manner is generally better than other patterns 0109 // which require pointer chasing: 0110 // 0111 // // Prefer using absl::NoDestructor<T> instead for the static variable. 0112 // const std::string& MyString() { 0113 // static const std::string* x = new std::string("foo"); 0114 // return *x; 0115 // } 0116 // 0117 template <typename T> 0118 class NoDestructor { 0119 public: 0120 // Forwards arguments to the T's constructor: calls T(args...). 0121 template <typename... Ts, 0122 // Disable this overload when it might collide with copy/move. 0123 typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...), 0124 void(NoDestructor&)>::value, 0125 int>::type = 0> 0126 explicit constexpr NoDestructor(Ts&&... args) 0127 : impl_(std::forward<Ts>(args)...) {} 0128 0129 // Forwards copy and move construction for T. Enables usage like this: 0130 // static NoDestructor<std::array<string, 3>> x{{{"1", "2", "3"}}}; 0131 // static NoDestructor<std::vector<int>> x{{1, 2, 3}}; 0132 explicit constexpr NoDestructor(const T& x) : impl_(x) {} 0133 explicit constexpr NoDestructor(T&& x) 0134 : impl_(std::move(x)) {} 0135 0136 // No copying. 0137 NoDestructor(const NoDestructor&) = delete; 0138 NoDestructor& operator=(const NoDestructor&) = delete; 0139 0140 // Pretend to be a smart pointer to T with deep constness. 0141 // Never returns a null pointer. 0142 T& operator*() { return *get(); } 0143 T* operator->() { return get(); } 0144 T* get() { return impl_.get(); } 0145 const T& operator*() const { return *get(); } 0146 const T* operator->() const { return get(); } 0147 const T* get() const { return impl_.get(); } 0148 0149 private: 0150 class DirectImpl { 0151 public: 0152 template <typename... Args> 0153 explicit constexpr DirectImpl(Args&&... args) 0154 : value_(std::forward<Args>(args)...) {} 0155 const T* get() const { return &value_; } 0156 T* get() { return &value_; } 0157 0158 private: 0159 T value_; 0160 }; 0161 0162 class PlacementImpl { 0163 public: 0164 template <typename... Args> 0165 explicit PlacementImpl(Args&&... args) { 0166 new (&space_) T(std::forward<Args>(args)...); 0167 } 0168 const T* get() const { 0169 return Launder(reinterpret_cast<const T*>(&space_)); 0170 } 0171 T* get() { return Launder(reinterpret_cast<T*>(&space_)); } 0172 0173 private: 0174 template <typename P> 0175 static P* Launder(P* p) { 0176 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L 0177 return std::launder(p); 0178 #elif ABSL_HAVE_BUILTIN(__builtin_launder) 0179 return __builtin_launder(p); 0180 #else 0181 // When `std::launder` or equivalent are not available, we rely on 0182 // undefined behavior, which works as intended on Abseil's officially 0183 // supported platforms as of Q3 2023. 0184 #if defined(__GNUC__) && !defined(__clang__) 0185 #pragma GCC diagnostic push 0186 #pragma GCC diagnostic ignored "-Wstrict-aliasing" 0187 #endif 0188 return p; 0189 #if defined(__GNUC__) && !defined(__clang__) 0190 #pragma GCC diagnostic pop 0191 #endif 0192 #endif 0193 } 0194 0195 alignas(T) unsigned char space_[sizeof(T)]; 0196 }; 0197 0198 // If the object is trivially destructible we use a member directly to avoid 0199 // potential once-init runtime initialization. It somewhat defeats the 0200 // purpose of NoDestructor in this case, but this makes the class more 0201 // friendly to generic code. 0202 std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl, 0203 PlacementImpl> 0204 impl_; 0205 }; 0206 0207 #ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 0208 // Provide 'Class Template Argument Deduction': the type of NoDestructor's T 0209 // will be the same type as the argument passed to NoDestructor's constructor. 0210 template <typename T> 0211 NoDestructor(T) -> NoDestructor<T>; 0212 #endif // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 0213 0214 ABSL_NAMESPACE_END 0215 } // namespace absl 0216 0217 #endif // ABSL_BASE_NO_DESTRUCTOR_H_
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |