![]() |
|
|||
File indexing completed on 2025-07-14 08:24:43
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 // absl::NoDestructor<T> is useful when when a variable has static storage 0025 // duration but its type has a non-trivial destructor. Global constructors are 0026 // not recommended because of the C++'s static initialization order fiasco (See 0027 // https://en.cppreference.com/w/cpp/language/siof). Global destructors are not 0028 // allowed due to similar concerns about destruction ordering. Using 0029 // absl::NoDestructor<T> as a function-local static prevents both of these 0030 // issues. 0031 // 0032 // See below for complete details. 0033 0034 0035 #ifndef ABSL_BASE_NO_DESTRUCTOR_H_ 0036 #define ABSL_BASE_NO_DESTRUCTOR_H_ 0037 0038 #include <new> 0039 #include <type_traits> 0040 #include <utility> 0041 0042 #include "absl/base/config.h" 0043 #include "absl/base/nullability.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 // ideally as 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 // Additionally, NoDestructor<T> provides the following benefits: 0065 // 0066 // * Never calls T's destructor for the object 0067 // * If the object is a function-local static variable, the type can be 0068 // lazily constructed. 0069 // 0070 // An object of type NoDestructor<T> is "trivially destructible" in the notion 0071 // that its destructor is never run. 0072 // 0073 // Usage as Function Scope Static Variables 0074 // 0075 // Function static objects will be lazily initialized within static storage: 0076 // 0077 // // Function scope. 0078 // const std::string& MyString() { 0079 // static const absl::NoDestructor<std::string> x("foo"); 0080 // return *x; 0081 // } 0082 // 0083 // For function static variables, NoDestructor avoids heap allocation and can be 0084 // inlined in static storage, resulting in exactly-once, thread-safe 0085 // construction of an object, and very fast access thereafter (the cost is a few 0086 // extra cycles). 0087 // 0088 // Using NoDestructor<T> in this manner is generally better than other patterns 0089 // which require pointer chasing: 0090 // 0091 // // Prefer using absl::NoDestructor<T> instead for the static variable. 0092 // const std::string& MyString() { 0093 // static const std::string* x = new std::string("foo"); 0094 // return *x; 0095 // } 0096 // 0097 // Usage as Global Static Variables 0098 // 0099 // NoDestructor<T> allows declaration of a global object of type T that has a 0100 // non-trivial destructor since its destructor is never run. However, such 0101 // objects still need to worry about initialization order, so such use is not 0102 // recommended, strongly discouraged by the Google C++ Style Guide, and outright 0103 // banned in Chromium. 0104 // See https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables 0105 // 0106 // // Global or namespace scope. 0107 // absl::NoDestructor<MyRegistry> reg{"foo", "bar", 8008}; 0108 // 0109 // Note that if your object already has a trivial destructor, you don't need to 0110 // use NoDestructor<T>. 0111 // 0112 template <typename T> 0113 class NoDestructor { 0114 public: 0115 // Forwards arguments to the T's constructor: calls T(args...). 0116 template <typename... Ts, 0117 // Disable this overload when it might collide with copy/move. 0118 typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...), 0119 void(NoDestructor&)>::value, 0120 int>::type = 0> 0121 explicit constexpr NoDestructor(Ts&&... args) 0122 : impl_(std::forward<Ts>(args)...) {} 0123 0124 // Forwards copy and move construction for T. Enables usage like this: 0125 // static NoDestructor<std::array<string, 3>> x{{{"1", "2", "3"}}}; 0126 // static NoDestructor<std::vector<int>> x{{1, 2, 3}}; 0127 explicit constexpr NoDestructor(const T& x) : impl_(x) {} 0128 explicit constexpr NoDestructor(T&& x) 0129 : impl_(std::move(x)) {} 0130 0131 // No copying. 0132 NoDestructor(const NoDestructor&) = delete; 0133 NoDestructor& operator=(const NoDestructor&) = delete; 0134 0135 // Pretend to be a smart pointer to T with deep constness. 0136 // Never returns a null pointer. 0137 T& operator*() { return *get(); } 0138 absl::Nonnull<T*> operator->() { return get(); } 0139 absl::Nonnull<T*> get() { return impl_.get(); } 0140 const T& operator*() const { return *get(); } 0141 absl::Nonnull<const T*> operator->() const { return get(); } 0142 absl::Nonnull<const T*> get() const { return impl_.get(); } 0143 0144 private: 0145 class DirectImpl { 0146 public: 0147 template <typename... Args> 0148 explicit constexpr DirectImpl(Args&&... args) 0149 : value_(std::forward<Args>(args)...) {} 0150 absl::Nonnull<const T*> get() const { return &value_; } 0151 absl::Nonnull<T*> get() { return &value_; } 0152 0153 private: 0154 T value_; 0155 }; 0156 0157 class PlacementImpl { 0158 public: 0159 template <typename... Args> 0160 explicit PlacementImpl(Args&&... args) { 0161 new (&space_) T(std::forward<Args>(args)...); 0162 } 0163 absl::Nonnull<const T*> get() const { 0164 return Launder(reinterpret_cast<const T*>(&space_)); 0165 } 0166 absl::Nonnull<T*> get() { return Launder(reinterpret_cast<T*>(&space_)); } 0167 0168 private: 0169 template <typename P> 0170 static absl::Nonnull<P*> Launder(absl::Nonnull<P*> p) { 0171 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L 0172 return std::launder(p); 0173 #elif ABSL_HAVE_BUILTIN(__builtin_launder) 0174 return __builtin_launder(p); 0175 #else 0176 // When `std::launder` or equivalent are not available, we rely on 0177 // undefined behavior, which works as intended on Abseil's officially 0178 // supported platforms as of Q3 2023. 0179 #if defined(__GNUC__) && !defined(__clang__) 0180 #pragma GCC diagnostic push 0181 #pragma GCC diagnostic ignored "-Wstrict-aliasing" 0182 #endif 0183 return p; 0184 #if defined(__GNUC__) && !defined(__clang__) 0185 #pragma GCC diagnostic pop 0186 #endif 0187 #endif 0188 } 0189 0190 alignas(T) unsigned char space_[sizeof(T)]; 0191 }; 0192 0193 // If the object is trivially destructible we use a member directly to avoid 0194 // potential once-init runtime initialization. It somewhat defeats the 0195 // purpose of NoDestructor in this case, but this makes the class more 0196 // friendly to generic code. 0197 std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl, 0198 PlacementImpl> 0199 impl_; 0200 }; 0201 0202 #ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 0203 // Provide 'Class Template Argument Deduction': the type of NoDestructor's T 0204 // will be the same type as the argument passed to NoDestructor's constructor. 0205 template <typename T> 0206 NoDestructor(T) -> NoDestructor<T>; 0207 #endif // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 0208 0209 ABSL_NAMESPACE_END 0210 } // namespace absl 0211 0212 #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 |
![]() ![]() |