no_destructor.h 4.4 KB

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