xref: /aosp_15_r20/external/libchrome/base/no_destructor.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #ifndef BASE_NO_DESTRUCTOR_H_
6*635a8641SAndroid Build Coastguard Worker #define BASE_NO_DESTRUCTOR_H_
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #include <new>
9*635a8641SAndroid Build Coastguard Worker #include <utility>
10*635a8641SAndroid Build Coastguard Worker 
11*635a8641SAndroid Build Coastguard Worker namespace base {
12*635a8641SAndroid Build Coastguard Worker 
13*635a8641SAndroid Build Coastguard Worker // A wrapper that makes it easy to create an object of type T with static
14*635a8641SAndroid Build Coastguard Worker // storage duration that:
15*635a8641SAndroid Build Coastguard Worker // - is only constructed on first access
16*635a8641SAndroid Build Coastguard Worker // - never invokes the destructor
17*635a8641SAndroid Build Coastguard Worker // in order to satisfy the styleguide ban on global constructors and
18*635a8641SAndroid Build Coastguard Worker // destructors.
19*635a8641SAndroid Build Coastguard Worker //
20*635a8641SAndroid Build Coastguard Worker // Runtime constant example:
21*635a8641SAndroid Build Coastguard Worker // const std::string& GetLineSeparator() {
22*635a8641SAndroid Build Coastguard Worker //  // Forwards to std::string(size_t, char, const Allocator&) constructor.
23*635a8641SAndroid Build Coastguard Worker //   static const base::NoDestructor<std::string> s(5, '-');
24*635a8641SAndroid Build Coastguard Worker //   return *s;
25*635a8641SAndroid Build Coastguard Worker // }
26*635a8641SAndroid Build Coastguard Worker //
27*635a8641SAndroid Build Coastguard Worker // More complex initialization with a lambda:
28*635a8641SAndroid Build Coastguard Worker // const std::string& GetSessionNonce() {
29*635a8641SAndroid Build Coastguard Worker //   static const base::NoDestructor<std::string> nonce([] {
30*635a8641SAndroid Build Coastguard Worker //     std::string s(16);
31*635a8641SAndroid Build Coastguard Worker //     crypto::RandString(s.data(), s.size());
32*635a8641SAndroid Build Coastguard Worker //     return s;
33*635a8641SAndroid Build Coastguard Worker //   }());
34*635a8641SAndroid Build Coastguard Worker //   return *nonce;
35*635a8641SAndroid Build Coastguard Worker // }
36*635a8641SAndroid Build Coastguard Worker //
37*635a8641SAndroid Build Coastguard Worker // NoDestructor<T> stores the object inline, so it also avoids a pointer
38*635a8641SAndroid Build Coastguard Worker // indirection and a malloc. Also note that since C++11 static local variable
39*635a8641SAndroid Build Coastguard Worker // initialization is thread-safe and so is this pattern. Code should prefer to
40*635a8641SAndroid Build Coastguard Worker // use NoDestructor<T> over:
41*635a8641SAndroid Build Coastguard Worker // - The CR_DEFINE_STATIC_LOCAL() helper macro.
42*635a8641SAndroid Build Coastguard Worker // - A function scoped static T* or T& that is dynamically initialized.
43*635a8641SAndroid Build Coastguard Worker // - A global base::LazyInstance<T>.
44*635a8641SAndroid Build Coastguard Worker //
45*635a8641SAndroid Build Coastguard Worker // Note that since the destructor is never run, this *will* leak memory if used
46*635a8641SAndroid Build Coastguard Worker // as a stack or member variable. Furthermore, a NoDestructor<T> should never
47*635a8641SAndroid Build Coastguard Worker // have global scope as that may require a static initializer.
48*635a8641SAndroid Build Coastguard Worker template <typename T>
49*635a8641SAndroid Build Coastguard Worker class NoDestructor {
50*635a8641SAndroid Build Coastguard Worker  public:
51*635a8641SAndroid Build Coastguard Worker   // Not constexpr; just write static constexpr T x = ...; if the value should
52*635a8641SAndroid Build Coastguard Worker   // be a constexpr.
53*635a8641SAndroid Build Coastguard Worker   template <typename... Args>
NoDestructor(Args &&...args)54*635a8641SAndroid Build Coastguard Worker   explicit NoDestructor(Args&&... args) {
55*635a8641SAndroid Build Coastguard Worker     new (storage_) T(std::forward<Args>(args)...);
56*635a8641SAndroid Build Coastguard Worker   }
57*635a8641SAndroid Build Coastguard Worker 
58*635a8641SAndroid Build Coastguard Worker   // Allows copy and move construction of the contained type, to allow
59*635a8641SAndroid Build Coastguard Worker   // construction from an initializer list, e.g. for std::vector.
NoDestructor(const T & x)60*635a8641SAndroid Build Coastguard Worker   explicit NoDestructor(const T& x) { new (storage_) T(x); }
NoDestructor(T && x)61*635a8641SAndroid Build Coastguard Worker   explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
62*635a8641SAndroid Build Coastguard Worker 
63*635a8641SAndroid Build Coastguard Worker   NoDestructor(const NoDestructor&) = delete;
64*635a8641SAndroid Build Coastguard Worker   NoDestructor& operator=(const NoDestructor&) = delete;
65*635a8641SAndroid Build Coastguard Worker 
66*635a8641SAndroid Build Coastguard Worker   ~NoDestructor() = default;
67*635a8641SAndroid Build Coastguard Worker 
68*635a8641SAndroid Build Coastguard Worker   const T& operator*() const { return *get(); }
69*635a8641SAndroid Build Coastguard Worker   T& operator*() { return *get(); }
70*635a8641SAndroid Build Coastguard Worker 
71*635a8641SAndroid Build Coastguard Worker   const T* operator->() const { return get(); }
72*635a8641SAndroid Build Coastguard Worker   T* operator->() { return get(); }
73*635a8641SAndroid Build Coastguard Worker 
get()74*635a8641SAndroid Build Coastguard Worker   const T* get() const { return reinterpret_cast<const T*>(storage_); }
get()75*635a8641SAndroid Build Coastguard Worker   T* get() { return reinterpret_cast<T*>(storage_); }
76*635a8641SAndroid Build Coastguard Worker 
77*635a8641SAndroid Build Coastguard Worker  private:
78*635a8641SAndroid Build Coastguard Worker   alignas(T) char storage_[sizeof(T)];
79*635a8641SAndroid Build Coastguard Worker 
80*635a8641SAndroid Build Coastguard Worker #if defined(LEAK_SANITIZER)
81*635a8641SAndroid Build Coastguard Worker   // TODO(https://crbug.com/812277): This is a hack to work around the fact
82*635a8641SAndroid Build Coastguard Worker   // that LSan doesn't seem to treat NoDestructor as a root for reachability
83*635a8641SAndroid Build Coastguard Worker   // analysis. This means that code like this:
84*635a8641SAndroid Build Coastguard Worker   //   static base::NoDestructor<std::vector<int>> v({1, 2, 3});
85*635a8641SAndroid Build Coastguard Worker   // is considered a leak. Using the standard leak sanitizer annotations to
86*635a8641SAndroid Build Coastguard Worker   // suppress leaks doesn't work: std::vector is implicitly constructed before
87*635a8641SAndroid Build Coastguard Worker   // calling the base::NoDestructor constructor.
88*635a8641SAndroid Build Coastguard Worker   //
89*635a8641SAndroid Build Coastguard Worker   // Unfortunately, I haven't been able to demonstrate this issue in simpler
90*635a8641SAndroid Build Coastguard Worker   // reproductions: until that's resolved, hold an explicit pointer to the
91*635a8641SAndroid Build Coastguard Worker   // placement-new'd object in leak sanitizer mode to help LSan realize that
92*635a8641SAndroid Build Coastguard Worker   // objects allocated by the contained type are still reachable.
93*635a8641SAndroid Build Coastguard Worker   T* storage_ptr_ = reinterpret_cast<T*>(storage_);
94*635a8641SAndroid Build Coastguard Worker #endif  // defined(LEAK_SANITIZER)
95*635a8641SAndroid Build Coastguard Worker };
96*635a8641SAndroid Build Coastguard Worker 
97*635a8641SAndroid Build Coastguard Worker }  // namespace base
98*635a8641SAndroid Build Coastguard Worker 
99*635a8641SAndroid Build Coastguard Worker #endif  // BASE_NO_DESTRUCTOR_H_
100