// Copyright 2022 gRPC authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H #define GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H #include #include #include #include "src/core/lib/gprpp/construct_destruct.h" namespace grpc_core { // NoDestruct is a wrapper around an object of type T that: // - stores the value inline - no heap allocation // - is non-copyable // - is eagerly constructed (i.e. the constructor is called when NoDestruct is // constructed) // - *NEVER* calls ~T() // It's useful in cases where no ordering can be assumed between destructors of // objects that need to refer to each other - such as at program destruction // time. // Examples: // // globally available object: // static NoDestruct g_foo(1, "foo", 2.0); // // used as: // g_foo->DoSomething(); // // singleton function: // Bar* BarSingleton() { // static NoDestruct bar(1, "bar", 2.0); // return &*bar; // } // The globally available version is constructed at program startup, and the // singleton version is constructed at the first call to BarSingleton(). // Neither Foo nor Bar instance will be destructed. template class NoDestruct { public: template explicit NoDestruct(Args&&... args) { static_assert(std::is_trivially_destructible>::value, "NoDestruct must be trivially destructible"); Construct(reinterpret_cast(&space_), std::forward(args)...); } NoDestruct(const NoDestruct&) = delete; NoDestruct& operator=(const NoDestruct&) = delete; ~NoDestruct() = default; T* operator->() { return get(); } const T* operator->() const { return get(); } T& operator*() { return *get(); } const T& operator*() const { return *get(); } T* get() { return reinterpret_cast(&space_); } const T* get() const { return reinterpret_cast(&space_); } private: typename std::aligned_storage::type space_; }; // Helper for when a program desires a single *process wide* instance of a // default constructed T to be always available. // The instance is constructed eagerly at program startup, so it's essentially // free to load the pointer to the instance. template class NoDestructSingleton { public: static T* Get() { return &*value_; } private: NoDestructSingleton() = delete; ~NoDestructSingleton() = delete; static NoDestruct value_; }; template NoDestruct NoDestructSingleton::value_; } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H