Commit bae24734 authored by Daniel Cheng's avatar Daniel Cheng Committed by Commit Bot

Allow initializer list usage with base::NoDestructor.

Also fixes a small typo in the NoDestructor documentation.

Change-Id: I87c1b1bcd383fd9644e03e2092f9456528e03860
Reviewed-on: https://chromium-review.googlesource.com/900342
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatardanakj <danakj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#536779}
parent 2d4fb27b
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef BASE_NO_DESTRUCTOR_H_ #ifndef BASE_NO_DESTRUCTOR_H_
#define BASE_NO_DESTRUCTOR_H_ #define BASE_NO_DESTRUCTOR_H_
#include <new>
#include <utility> #include <utility>
namespace base { namespace base {
...@@ -20,7 +21,7 @@ namespace base { ...@@ -20,7 +21,7 @@ namespace base {
// const std::string& GetLineSeparator() { // const std::string& GetLineSeparator() {
// // Forwards to std::string(size_t, char, const Allocator&) constructor. // // Forwards to std::string(size_t, char, const Allocator&) constructor.
// static const base::NoDestructor<std::string> s(5, '-'); // static const base::NoDestructor<std::string> s(5, '-');
// return s; // return *s;
// } // }
// //
// More complex initialization with a lambda: // More complex initialization with a lambda:
...@@ -49,9 +50,17 @@ class NoDestructor { ...@@ -49,9 +50,17 @@ class NoDestructor {
// be a constexpr. // be a constexpr.
template <typename... Args> template <typename... Args>
explicit NoDestructor(Args&&... args) { explicit NoDestructor(Args&&... args) {
new (get()) T(std::forward<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; ~NoDestructor() = default;
const T& operator*() const { return *get(); } const T& operator*() const { return *get(); }
...@@ -60,11 +69,27 @@ class NoDestructor { ...@@ -60,11 +69,27 @@ class NoDestructor {
const T* operator->() const { return get(); } const T* operator->() const { return get(); }
T* operator->() { return get(); } T* operator->() { return get(); }
const T* get() const { return reinterpret_cast<const T*>(&storage_); } const T* get() const { return reinterpret_cast<const T*>(storage_); }
T* get() { return reinterpret_cast<T*>(&storage_); } T* get() { return reinterpret_cast<T*>(storage_); }
private: private:
alignas(T) char storage_[sizeof(T)]; 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 } // namespace base
......
...@@ -62,6 +62,10 @@ TEST(NoDestructorTest, Accessors) { ...@@ -62,6 +62,10 @@ TEST(NoDestructorTest, Accessors) {
EXPECT_EQ(0, awesome.get()->compare("awesome")); EXPECT_EQ(0, awesome.get()->compare("awesome"));
} }
TEST(NoDestructorTest, InitializerList) {
static NoDestructor<std::vector<std::string>> vector({"a", "b", "c"});
}
} // namespace } // namespace
} // namespace base } // namespace base
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment