Back to home page

EIC code displayed by LXR

 
 

    


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_