xref: /aosp_15_r20/external/cronet/base/no_destructor.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_NO_DESTRUCTOR_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_NO_DESTRUCTOR_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <new>
9*6777b538SAndroid Build Coastguard Worker #include <type_traits>
10*6777b538SAndroid Build Coastguard Worker #include <utility>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker namespace base {
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker // Helper type to create a function-local static variable of type `T` when `T`
15*6777b538SAndroid Build Coastguard Worker // has a non-trivial destructor. Storing a `T` in a `base::NoDestructor<T>` will
16*6777b538SAndroid Build Coastguard Worker // prevent `~T()` from running, even when the variable goes out of scope.
17*6777b538SAndroid Build Coastguard Worker //
18*6777b538SAndroid Build Coastguard Worker // Useful when a variable has static storage duration but its type has a
19*6777b538SAndroid Build Coastguard Worker // non-trivial destructor. Chromium bans global constructors and destructors:
20*6777b538SAndroid Build Coastguard Worker // using a function-local static variable prevents the former, while using
21*6777b538SAndroid Build Coastguard Worker // `base::NoDestructor<T>` prevents the latter.
22*6777b538SAndroid Build Coastguard Worker //
23*6777b538SAndroid Build Coastguard Worker // ## Caveats
24*6777b538SAndroid Build Coastguard Worker //
25*6777b538SAndroid Build Coastguard Worker // - Must not be used for locals or fields; by definition, this does not run
26*6777b538SAndroid Build Coastguard Worker //   destructors, and this will likely lead to memory leaks and other
27*6777b538SAndroid Build Coastguard Worker //   surprising and undesirable behaviour.
28*6777b538SAndroid Build Coastguard Worker //
29*6777b538SAndroid Build Coastguard Worker // - If `T` is not constexpr constructible, must be a function-local static
30*6777b538SAndroid Build Coastguard Worker //   variable, since a global `NoDestructor<T>` will still generate a static
31*6777b538SAndroid Build Coastguard Worker //   initializer.
32*6777b538SAndroid Build Coastguard Worker //
33*6777b538SAndroid Build Coastguard Worker // - If `T` is constinit constructible, may be used as a global, but mark the
34*6777b538SAndroid Build Coastguard Worker //   global `constinit`.
35*6777b538SAndroid Build Coastguard Worker //
36*6777b538SAndroid Build Coastguard Worker // - If the data is rarely used, consider creating it on demand rather than
37*6777b538SAndroid Build Coastguard Worker //   caching it for the lifetime of the program. Though `base::NoDestructor<T>`
38*6777b538SAndroid Build Coastguard Worker //   does not heap allocate, the compiler still reserves space in bss for
39*6777b538SAndroid Build Coastguard Worker //   storing `T`, which costs memory at runtime.
40*6777b538SAndroid Build Coastguard Worker //
41*6777b538SAndroid Build Coastguard Worker // - If `T` is trivially destructible, do not use `base::NoDestructor<T>`:
42*6777b538SAndroid Build Coastguard Worker //
43*6777b538SAndroid Build Coastguard Worker //     const uint64_t GetUnstableSessionSeed() {
44*6777b538SAndroid Build Coastguard Worker //       // No need to use `base::NoDestructor<T>` as `uint64_t` is trivially
45*6777b538SAndroid Build Coastguard Worker //       // destructible and does not require a global destructor.
46*6777b538SAndroid Build Coastguard Worker //       static const uint64_t kSessionSeed = base::RandUint64();
47*6777b538SAndroid Build Coastguard Worker //       return kSessionSeed;
48*6777b538SAndroid Build Coastguard Worker //     }
49*6777b538SAndroid Build Coastguard Worker //
50*6777b538SAndroid Build Coastguard Worker // ## Example Usage
51*6777b538SAndroid Build Coastguard Worker //
52*6777b538SAndroid Build Coastguard Worker // const std::string& GetDefaultText() {
53*6777b538SAndroid Build Coastguard Worker //   // Required since `static const std::string` requires a global destructor.
54*6777b538SAndroid Build Coastguard Worker //   static const base::NoDestructor<std::string> s("Hello world!");
55*6777b538SAndroid Build Coastguard Worker //   return *s;
56*6777b538SAndroid Build Coastguard Worker // }
57*6777b538SAndroid Build Coastguard Worker //
58*6777b538SAndroid Build Coastguard Worker // More complex initialization using a lambda:
59*6777b538SAndroid Build Coastguard Worker //
60*6777b538SAndroid Build Coastguard Worker // const std::string& GetRandomNonce() {
61*6777b538SAndroid Build Coastguard Worker //   // `nonce` is initialized with random data the first time this function is
62*6777b538SAndroid Build Coastguard Worker //   // called, but its value is fixed thereafter.
63*6777b538SAndroid Build Coastguard Worker //   static const base::NoDestructor<std::string> nonce([] {
64*6777b538SAndroid Build Coastguard Worker //     std::string s(16);
65*6777b538SAndroid Build Coastguard Worker //     crypto::RandString(s.data(), s.size());
66*6777b538SAndroid Build Coastguard Worker //     return s;
67*6777b538SAndroid Build Coastguard Worker //   }());
68*6777b538SAndroid Build Coastguard Worker //   return *nonce;
69*6777b538SAndroid Build Coastguard Worker // }
70*6777b538SAndroid Build Coastguard Worker //
71*6777b538SAndroid Build Coastguard Worker // ## Thread safety
72*6777b538SAndroid Build Coastguard Worker //
73*6777b538SAndroid Build Coastguard Worker // Initialisation of function-local static variables is thread-safe since C++11.
74*6777b538SAndroid Build Coastguard Worker // The standard guarantees that:
75*6777b538SAndroid Build Coastguard Worker //
76*6777b538SAndroid Build Coastguard Worker // - function-local static variables will be initialised the first time
77*6777b538SAndroid Build Coastguard Worker //   execution passes through the declaration.
78*6777b538SAndroid Build Coastguard Worker //
79*6777b538SAndroid Build Coastguard Worker // - if another thread's execution concurrently passes through the declaration
80*6777b538SAndroid Build Coastguard Worker //   in the middle of initialisation, that thread will wait for the in-progress
81*6777b538SAndroid Build Coastguard Worker //   initialisation to complete.
82*6777b538SAndroid Build Coastguard Worker template <typename T>
83*6777b538SAndroid Build Coastguard Worker class NoDestructor {
84*6777b538SAndroid Build Coastguard Worker  public:
85*6777b538SAndroid Build Coastguard Worker   static_assert(!(std::is_trivially_constructible_v<T> &&
86*6777b538SAndroid Build Coastguard Worker                   std::is_trivially_destructible_v<T>),
87*6777b538SAndroid Build Coastguard Worker                 "T is trivially constructible and destructible; please use a "
88*6777b538SAndroid Build Coastguard Worker                 "constinit object of type T directly instead");
89*6777b538SAndroid Build Coastguard Worker 
90*6777b538SAndroid Build Coastguard Worker   static_assert(
91*6777b538SAndroid Build Coastguard Worker       !std::is_trivially_destructible_v<T>,
92*6777b538SAndroid Build Coastguard Worker       "T is trivially destructible; please use a function-local static "
93*6777b538SAndroid Build Coastguard Worker       "of type T directly instead");
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker   // Not constexpr; just write static constexpr T x = ...; if the value should
96*6777b538SAndroid Build Coastguard Worker   // be a constexpr.
97*6777b538SAndroid Build Coastguard Worker   template <typename... Args>
NoDestructor(Args &&...args)98*6777b538SAndroid Build Coastguard Worker   explicit NoDestructor(Args&&... args) {
99*6777b538SAndroid Build Coastguard Worker     new (storage_) T(std::forward<Args>(args)...);
100*6777b538SAndroid Build Coastguard Worker   }
101*6777b538SAndroid Build Coastguard Worker 
102*6777b538SAndroid Build Coastguard Worker   // Allows copy and move construction of the contained type, to allow
103*6777b538SAndroid Build Coastguard Worker   // construction from an initializer list, e.g. for std::vector.
NoDestructor(const T & x)104*6777b538SAndroid Build Coastguard Worker   explicit NoDestructor(const T& x) { new (storage_) T(x); }
NoDestructor(T && x)105*6777b538SAndroid Build Coastguard Worker   explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker   NoDestructor(const NoDestructor&) = delete;
108*6777b538SAndroid Build Coastguard Worker   NoDestructor& operator=(const NoDestructor&) = delete;
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker   ~NoDestructor() = default;
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   const T& operator*() const { return *get(); }
113*6777b538SAndroid Build Coastguard Worker   T& operator*() { return *get(); }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker   const T* operator->() const { return get(); }
116*6777b538SAndroid Build Coastguard Worker   T* operator->() { return get(); }
117*6777b538SAndroid Build Coastguard Worker 
get()118*6777b538SAndroid Build Coastguard Worker   const T* get() const { return reinterpret_cast<const T*>(storage_); }
get()119*6777b538SAndroid Build Coastguard Worker   T* get() { return reinterpret_cast<T*>(storage_); }
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker  private:
122*6777b538SAndroid Build Coastguard Worker   alignas(T) char storage_[sizeof(T)];
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker #if defined(LEAK_SANITIZER)
125*6777b538SAndroid Build Coastguard Worker   // TODO(https://crbug.com/812277): This is a hack to work around the fact
126*6777b538SAndroid Build Coastguard Worker   // that LSan doesn't seem to treat NoDestructor as a root for reachability
127*6777b538SAndroid Build Coastguard Worker   // analysis. This means that code like this:
128*6777b538SAndroid Build Coastguard Worker   //   static base::NoDestructor<std::vector<int>> v({1, 2, 3});
129*6777b538SAndroid Build Coastguard Worker   // is considered a leak. Using the standard leak sanitizer annotations to
130*6777b538SAndroid Build Coastguard Worker   // suppress leaks doesn't work: std::vector is implicitly constructed before
131*6777b538SAndroid Build Coastguard Worker   // calling the base::NoDestructor constructor.
132*6777b538SAndroid Build Coastguard Worker   //
133*6777b538SAndroid Build Coastguard Worker   // Unfortunately, I haven't been able to demonstrate this issue in simpler
134*6777b538SAndroid Build Coastguard Worker   // reproductions: until that's resolved, hold an explicit pointer to the
135*6777b538SAndroid Build Coastguard Worker   // placement-new'd object in leak sanitizer mode to help LSan realize that
136*6777b538SAndroid Build Coastguard Worker   // objects allocated by the contained type are still reachable.
137*6777b538SAndroid Build Coastguard Worker   T* storage_ptr_ = reinterpret_cast<T*>(storage_);
138*6777b538SAndroid Build Coastguard Worker #endif  // defined(LEAK_SANITIZER)
139*6777b538SAndroid Build Coastguard Worker };
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker }  // namespace base
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker #endif  // BASE_NO_DESTRUCTOR_H_
144