1 // Copyright 2022 gRPC authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H 16 #define GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H 17 18 #include <grpc/support/port_platform.h> 19 20 #include <type_traits> 21 #include <utility> 22 23 #include "src/core/lib/gprpp/construct_destruct.h" 24 25 namespace grpc_core { 26 27 // NoDestruct<T> is a wrapper around an object of type T that: 28 // - stores the value inline - no heap allocation 29 // - is non-copyable 30 // - is eagerly constructed (i.e. the constructor is called when NoDestruct is 31 // constructed) 32 // - *NEVER* calls ~T() 33 // It's useful in cases where no ordering can be assumed between destructors of 34 // objects that need to refer to each other - such as at program destruction 35 // time. 36 // Examples: 37 // // globally available object: 38 // static NoDestruct<Foo> g_foo(1, "foo", 2.0); 39 // // used as: 40 // g_foo->DoSomething(); 41 // // singleton function: 42 // Bar* BarSingleton() { 43 // static NoDestruct<Bar> bar(1, "bar", 2.0); 44 // return &*bar; 45 // } 46 // The globally available version is constructed at program startup, and the 47 // singleton version is constructed at the first call to BarSingleton(). 48 // Neither Foo nor Bar instance will be destructed. 49 template <typename T> 50 class NoDestruct { 51 public: 52 template <typename... Args> NoDestruct(Args &&...args)53 explicit NoDestruct(Args&&... args) { 54 static_assert(std::is_trivially_destructible<NoDestruct<T>>::value, 55 "NoDestruct must be trivially destructible"); 56 Construct(reinterpret_cast<T*>(&space_), std::forward<Args>(args)...); 57 } 58 NoDestruct(const NoDestruct&) = delete; 59 NoDestruct& operator=(const NoDestruct&) = delete; 60 ~NoDestruct() = default; 61 62 T* operator->() { return get(); } 63 const T* operator->() const { return get(); } 64 T& operator*() { return *get(); } 65 const T& operator*() const { return *get(); } 66 get()67 T* get() { return reinterpret_cast<T*>(&space_); } get()68 const T* get() const { return reinterpret_cast<const T*>(&space_); } 69 70 private: 71 typename std::aligned_storage<sizeof(T), alignof(T)>::type space_; 72 }; 73 74 // Helper for when a program desires a single *process wide* instance of a 75 // default constructed T to be always available. 76 // The instance is constructed eagerly at program startup, so it's essentially 77 // free to load the pointer to the instance. 78 template <typename T> 79 class NoDestructSingleton { 80 public: Get()81 static T* Get() { return &*value_; } 82 83 private: 84 NoDestructSingleton() = delete; 85 ~NoDestructSingleton() = delete; 86 87 static NoDestruct<T> value_; 88 }; 89 90 template <typename T> 91 NoDestruct<T> NoDestructSingleton<T>::value_; 92 93 } // namespace grpc_core 94 95 #endif // GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H 96