You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.6 KiB
130 lines
4.6 KiB
From c334673e96ce73cbf1a693c7c85b1450fcd3571c Mon Sep 17 00:00:00 2001
|
|
From: Ben Chan <benchan@chromium.org>
|
|
Date: Fri, 2 Nov 2018 23:07:01 -0700
|
|
Subject: [PATCH] libchrome: add base::NoDestructor<T>
|
|
|
|
CL:869351 introduces base::NoDestructor<T>, which is preferred in new
|
|
code as a drop-in replacement for a function scoped static T* or T& that
|
|
is dynamically initialized, and a global base::LazyInstance<T>.
|
|
|
|
This CL patches libchrome to pull in base/no_destructor.h at r599267, so
|
|
that we can migrate existing Chrome OS code to use base::NoDestructor<T>
|
|
before the next libchrome uprev.
|
|
|
|
BUG=None
|
|
TEST=`emerge-$BOARD librchrome`
|
|
|
|
Change-Id: I791a70e10da6318ea81eaaec869ba4702361289e
|
|
---
|
|
base/no_destructor.h | 98 ++++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 98 insertions(+)
|
|
create mode 100644 base/no_destructor.h
|
|
|
|
diff --git base/no_destructor.h base/no_destructor.h
|
|
new file mode 100644
|
|
index 0000000..21cfef8
|
|
--- /dev/null
|
|
+++ base/no_destructor.h
|
|
@@ -0,0 +1,98 @@
|
|
+// Copyright 2018 The Chromium Authors. All rights reserved.
|
|
+// Use of this source code is governed by a BSD-style license that can be
|
|
+// found in the LICENSE file.
|
|
+
|
|
+#ifndef BASE_NO_DESTRUCTOR_H_
|
|
+#define BASE_NO_DESTRUCTOR_H_
|
|
+
|
|
+#include <new>
|
|
+#include <utility>
|
|
+
|
|
+namespace base {
|
|
+
|
|
+// A wrapper that makes it easy to create an object of type T with static
|
|
+// storage duration that:
|
|
+// - is only constructed on first access
|
|
+// - never invokes the destructor
|
|
+// in order to satisfy the styleguide ban on global constructors and
|
|
+// destructors.
|
|
+//
|
|
+// Runtime constant example:
|
|
+// const std::string& GetLineSeparator() {
|
|
+// // Forwards to std::string(size_t, char, const Allocator&) constructor.
|
|
+// static const base::NoDestructor<std::string> s(5, '-');
|
|
+// return *s;
|
|
+// }
|
|
+//
|
|
+// More complex initialization with a lambda:
|
|
+// const std::string& GetSessionNonce() {
|
|
+// static const base::NoDestructor<std::string> nonce([] {
|
|
+// std::string s(16);
|
|
+// crypto::RandString(s.data(), s.size());
|
|
+// return s;
|
|
+// }());
|
|
+// return *nonce;
|
|
+// }
|
|
+//
|
|
+// NoDestructor<T> stores the object inline, so it also avoids a pointer
|
|
+// indirection and a malloc. Also note that since C++11 static local variable
|
|
+// initialization is thread-safe and so is this pattern. Code should prefer to
|
|
+// use NoDestructor<T> over:
|
|
+// - A function scoped static T* or T& that is dynamically initialized.
|
|
+// - A global base::LazyInstance<T>.
|
|
+//
|
|
+// Note that since the destructor is never run, this *will* leak memory if used
|
|
+// as a stack or member variable. Furthermore, a NoDestructor<T> should never
|
|
+// have global scope as that may require a static initializer.
|
|
+template <typename T>
|
|
+class NoDestructor {
|
|
+ public:
|
|
+ // Not constexpr; just write static constexpr T x = ...; if the value should
|
|
+ // be a constexpr.
|
|
+ template <typename... Args>
|
|
+ explicit NoDestructor(Args&&... args) {
|
|
+ new (storage_) T(std::forward<Args>(args)...);
|
|
+ }
|
|
+
|
|
+ // Allows copy and move construction of the contained type, to allow
|
|
+ // construction from an initializer list, e.g. for std::vector.
|
|
+ explicit NoDestructor(const T& x) { new (storage_) T(x); }
|
|
+ explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
|
|
+
|
|
+ NoDestructor(const NoDestructor&) = delete;
|
|
+ NoDestructor& operator=(const NoDestructor&) = delete;
|
|
+
|
|
+ ~NoDestructor() = default;
|
|
+
|
|
+ const T& operator*() const { return *get(); }
|
|
+ T& operator*() { return *get(); }
|
|
+
|
|
+ const T* operator->() const { return get(); }
|
|
+ T* operator->() { return get(); }
|
|
+
|
|
+ const T* get() const { return reinterpret_cast<const T*>(storage_); }
|
|
+ T* get() { return reinterpret_cast<T*>(storage_); }
|
|
+
|
|
+ private:
|
|
+ alignas(T) char storage_[sizeof(T)];
|
|
+
|
|
+#if defined(LEAK_SANITIZER)
|
|
+ // TODO(https://crbug.com/812277): This is a hack to work around the fact
|
|
+ // that LSan doesn't seem to treat NoDestructor as a root for reachability
|
|
+ // analysis. This means that code like this:
|
|
+ // static base::NoDestructor<std::vector<int>> v({1, 2, 3});
|
|
+ // is considered a leak. Using the standard leak sanitizer annotations to
|
|
+ // suppress leaks doesn't work: std::vector is implicitly constructed before
|
|
+ // calling the base::NoDestructor constructor.
|
|
+ //
|
|
+ // Unfortunately, I haven't been able to demonstrate this issue in simpler
|
|
+ // reproductions: until that's resolved, hold an explicit pointer to the
|
|
+ // placement-new'd object in leak sanitizer mode to help LSan realize that
|
|
+ // objects allocated by the contained type are still reachable.
|
|
+ T* storage_ptr_ = reinterpret_cast<T*>(storage_);
|
|
+#endif // defined(LEAK_SANITIZER)
|
|
+};
|
|
+
|
|
+} // namespace base
|
|
+
|
|
+#endif // BASE_NO_DESTRUCTOR_H_
|
|
--
|
|
2.19.1.930.g4563a0d9d0-goog
|
|
|