1 #pragma once 2 3 /* 4 * Copyright (C) 2019 The Android Open Source Project 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #include <utility> 20 21 #include "android-base/macros.h" 22 23 namespace android { 24 namespace base { 25 26 // A wrapper that makes it easy to create an object of type T with static 27 // storage duration that: 28 // - is only constructed on first access 29 // - never invokes the destructor 30 // in order to satisfy the styleguide ban on global constructors and 31 // destructors. 32 // 33 // Runtime constant example: 34 // const std::string& GetLineSeparator() { 35 // // Forwards to std::string(size_t, char, const Allocator&) constructor. 36 // static const base::NoDestructor<std::string> s(5, '-'); 37 // return *s; 38 // } 39 // 40 // More complex initialization with a lambda: 41 // const std::string& GetSessionNonce() { 42 // static const base::NoDestructor<std::string> nonce([] { 43 // std::string s(16); 44 // crypto::RandString(s.data(), s.size()); 45 // return s; 46 // }()); 47 // return *nonce; 48 // } 49 // 50 // NoDestructor<T> stores the object inline, so it also avoids a pointer 51 // indirection and a malloc. Also note that since C++11 static local variable 52 // initialization is thread-safe and so is this pattern. Code should prefer to 53 // use NoDestructor<T> over: 54 // - A function scoped static T* or T& that is dynamically initialized. 55 // - A global base::LazyInstance<T>. 56 // 57 // Note that since the destructor is never run, this *will* leak memory if used 58 // as a stack or member variable. Furthermore, a NoDestructor<T> should never 59 // have global scope as that may require a static initializer. 60 template <typename T> 61 class NoDestructor { 62 public: 63 // Not constexpr; just write static constexpr T x = ...; if the value should 64 // be a constexpr. 65 template <typename... Args> NoDestructor(Args &&...args)66 explicit NoDestructor(Args&&... args) { 67 new (storage_) T(std::forward<Args>(args)...); 68 } 69 70 // Allows copy and move construction of the contained type, to allow 71 // construction from an initializer list, e.g. for std::vector. NoDestructor(const T & x)72 explicit NoDestructor(const T& x) { new (storage_) T(x); } NoDestructor(T && x)73 explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); } 74 75 NoDestructor(const NoDestructor&) = delete; 76 NoDestructor& operator=(const NoDestructor&) = delete; 77 78 ~NoDestructor() = default; 79 80 const T& operator*() const { return *get(); } 81 T& operator*() { return *get(); } 82 83 const T* operator->() const { return get(); } 84 T* operator->() { return get(); } 85 get()86 const T* get() const { return reinterpret_cast<const T*>(storage_); } get()87 T* get() { return reinterpret_cast<T*>(storage_); } 88 89 private: 90 alignas(T) char storage_[sizeof(T)]; 91 }; 92 93 } // namespace base 94 } // namespace android 95