NeverDestroyed.h (2475B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_NeverDestroyed_h 8 #define mozilla_NeverDestroyed_h 9 10 #include <new> 11 #include <type_traits> 12 #include <utility> 13 #include "mozilla/Attributes.h" 14 15 namespace mozilla { 16 17 // Helper type for creating a local static member of type `T` when `T` has a 18 // non-trivial static destructor. When used for the local static value, this 19 // type will avoid introducing a static destructor for these types, as they 20 // will survive until shutdown. 21 // 22 // This can be very useful to avoid static destructors, which are heavily 23 // discouraged. Using this type is unnecessary if `T` already has a trivial 24 // destructor, and may introduce unnecessary extra overhead. 25 // 26 // This type must only be used with static local members within a function, 27 // which will be enforced by the clang static analysis. 28 template <typename T> 29 class MOZ_STATIC_LOCAL_CLASS 30 MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS NeverDestroyed { 31 public: 32 static_assert( 33 !std::is_trivially_destructible_v<T>, 34 "NeverDestroyed is unnecessary for trivially destructable types"); 35 36 // Allow constructing the inner type. 37 // This isn't constexpr, as it requires invoking placement-new. See the 38 // comment on `mStorage`. 39 template <typename... U> 40 explicit NeverDestroyed(U&&... aArgs) { 41 new (mStorage) T(std::forward<U>(aArgs)...); 42 } 43 44 const T& operator*() const { return *get(); } 45 T& operator*() { return *get(); } 46 47 const T* operator->() const { return get(); } 48 T* operator->() { return get(); } 49 50 const T* get() const { return reinterpret_cast<const T*>(mStorage); } 51 T* get() { return reinterpret_cast<T*>(mStorage); } 52 53 // Block copy & move constructor, as the type is not safe to copy. 54 NeverDestroyed(const NeverDestroyed&) = delete; 55 NeverDestroyed& operator=(const NeverDestroyed&) = delete; 56 57 private: 58 // Correctly aligned storage for the type. We unfortunately can't use a union 59 // for alignment & constexpr initialization as that would require an explicit 60 // destructor declaration, making `NeverDestroyed` non-trivially destructable. 61 alignas(T) char mStorage[sizeof(T)]; 62 }; 63 64 }; // namespace mozilla 65 66 #endif // mozilla_NeverDestroyed_h