• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1From c334673e96ce73cbf1a693c7c85b1450fcd3571c Mon Sep 17 00:00:00 2001
2From: Ben Chan <benchan@chromium.org>
3Date: Fri, 2 Nov 2018 23:07:01 -0700
4Subject: [PATCH] libchrome: add base::NoDestructor<T>
5
6CL:869351 introduces base::NoDestructor<T>, which is preferred in new
7code as a drop-in replacement for a function scoped static T* or T& that
8is dynamically initialized, and a global base::LazyInstance<T>.
9
10This CL patches libchrome to pull in base/no_destructor.h at r599267, so
11that we can migrate existing Chrome OS code to use base::NoDestructor<T>
12before the next libchrome uprev.
13
14BUG=None
15TEST=`emerge-$BOARD librchrome`
16
17Change-Id: I791a70e10da6318ea81eaaec869ba4702361289e
18---
19 base/no_destructor.h | 98 ++++++++++++++++++++++++++++++++++++++++++++
20 1 file changed, 98 insertions(+)
21 create mode 100644 base/no_destructor.h
22
23diff --git base/no_destructor.h base/no_destructor.h
24new file mode 100644
25index 0000000..21cfef8
26--- /dev/null
27+++ base/no_destructor.h
28@@ -0,0 +1,98 @@
29+// Copyright 2018 The Chromium Authors. All rights reserved.
30+// Use of this source code is governed by a BSD-style license that can be
31+// found in the LICENSE file.
32+
33+#ifndef BASE_NO_DESTRUCTOR_H_
34+#define BASE_NO_DESTRUCTOR_H_
35+
36+#include <new>
37+#include <utility>
38+
39+namespace base {
40+
41+// A wrapper that makes it easy to create an object of type T with static
42+// storage duration that:
43+// - is only constructed on first access
44+// - never invokes the destructor
45+// in order to satisfy the styleguide ban on global constructors and
46+// destructors.
47+//
48+// Runtime constant example:
49+// const std::string& GetLineSeparator() {
50+//  // Forwards to std::string(size_t, char, const Allocator&) constructor.
51+//   static const base::NoDestructor<std::string> s(5, '-');
52+//   return *s;
53+// }
54+//
55+// More complex initialization with a lambda:
56+// const std::string& GetSessionNonce() {
57+//   static const base::NoDestructor<std::string> nonce([] {
58+//     std::string s(16);
59+//     crypto::RandString(s.data(), s.size());
60+//     return s;
61+//   }());
62+//   return *nonce;
63+// }
64+//
65+// NoDestructor<T> stores the object inline, so it also avoids a pointer
66+// indirection and a malloc. Also note that since C++11 static local variable
67+// initialization is thread-safe and so is this pattern. Code should prefer to
68+// use NoDestructor<T> over:
69+// - A function scoped static T* or T& that is dynamically initialized.
70+// - A global base::LazyInstance<T>.
71+//
72+// Note that since the destructor is never run, this *will* leak memory if used
73+// as a stack or member variable. Furthermore, a NoDestructor<T> should never
74+// have global scope as that may require a static initializer.
75+template <typename T>
76+class NoDestructor {
77+ public:
78+  // Not constexpr; just write static constexpr T x = ...; if the value should
79+  // be a constexpr.
80+  template <typename... Args>
81+  explicit NoDestructor(Args&&... args) {
82+    new (storage_) T(std::forward<Args>(args)...);
83+  }
84+
85+  // Allows copy and move construction of the contained type, to allow
86+  // construction from an initializer list, e.g. for std::vector.
87+  explicit NoDestructor(const T& x) { new (storage_) T(x); }
88+  explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
89+
90+  NoDestructor(const NoDestructor&) = delete;
91+  NoDestructor& operator=(const NoDestructor&) = delete;
92+
93+  ~NoDestructor() = default;
94+
95+  const T& operator*() const { return *get(); }
96+  T& operator*() { return *get(); }
97+
98+  const T* operator->() const { return get(); }
99+  T* operator->() { return get(); }
100+
101+  const T* get() const { return reinterpret_cast<const T*>(storage_); }
102+  T* get() { return reinterpret_cast<T*>(storage_); }
103+
104+ private:
105+  alignas(T) char storage_[sizeof(T)];
106+
107+#if defined(LEAK_SANITIZER)
108+  // TODO(https://crbug.com/812277): This is a hack to work around the fact
109+  // that LSan doesn't seem to treat NoDestructor as a root for reachability
110+  // analysis. This means that code like this:
111+  //   static base::NoDestructor<std::vector<int>> v({1, 2, 3});
112+  // is considered a leak. Using the standard leak sanitizer annotations to
113+  // suppress leaks doesn't work: std::vector is implicitly constructed before
114+  // calling the base::NoDestructor constructor.
115+  //
116+  // Unfortunately, I haven't been able to demonstrate this issue in simpler
117+  // reproductions: until that's resolved, hold an explicit pointer to the
118+  // placement-new'd object in leak sanitizer mode to help LSan realize that
119+  // objects allocated by the contained type are still reachable.
120+  T* storage_ptr_ = reinterpret_cast<T*>(storage_);
121+#endif  // defined(LEAK_SANITIZER)
122+};
123+
124+}  // namespace base
125+
126+#endif  // BASE_NO_DESTRUCTOR_H_
127--
1282.19.1.930.g4563a0d9d0-goog
129
130