1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <cassert> 20 #include <cstdlib> 21 #include <type_traits> 22 #include <utility> 23 24 namespace folly { 25 26 /** 27 * A helper class to allow a DelayedDestruction object to be instantiated on 28 * the stack. 29 * 30 * This class derives from an existing DelayedDestruction type and makes the 31 * destructor public again. This allows objects of this type to be declared on 32 * the stack or directly inside another class. Normally DelayedDestruction 33 * objects must be dynamically allocated on the heap. 34 * 35 * However, the trade-off is that you lose some of the protections provided by 36 * DelayedDestruction::destroy(). DelayedDestruction::destroy() will 37 * automatically delay destruction of the object until it is safe to do so. 38 * If you use UndelayedDestruction, you become responsible for ensuring that 39 * you only destroy the object where it is safe to do so. Attempting to 40 * destroy a UndelayedDestruction object while it has a non-zero destructor 41 * guard count will abort the program. 42 */ 43 template <typename TDD> 44 class UndelayedDestruction : public TDD { 45 public: 46 // We could just use constructor inheritance, but not all compilers 47 // support that. So, just use a forwarding constructor. 48 // 49 // Ideally we would use std::enable_if<> and std::is_constructible<> to 50 // provide only constructor methods that are valid for our parent class. 51 // Unfortunately std::is_constructible<> doesn't work for types that aren't 52 // destructible. In gcc-4.6 it results in a compiler error. In the latest 53 // gcc code it looks like it has been fixed to return false. (The language 54 // in the standard seems to indicate that returning false is the correct 55 // behavior for non-destructible types, which is unfortunate.) 56 template <typename... Args> UndelayedDestruction(Args &&...args)57 explicit UndelayedDestruction(Args&&... args) 58 : TDD(std::forward<Args>(args)...) {} 59 60 /** 61 * Public destructor. 62 * 63 * The caller is responsible for ensuring that the object is only destroyed 64 * where it is safe to do so. (i.e., when the destructor guard count is 0). 65 * 66 * The exact conditions for meeting this may be dependent upon your class 67 * semantics. Typically you are only guaranteed that it is safe to destroy 68 * the object directly from the event loop (e.g., directly from a 69 * EventBase::LoopCallback), or when the event loop is stopped. 70 */ ~UndelayedDestruction()71 ~UndelayedDestruction() override { 72 // Crash if the caller is destroying us with outstanding destructor guards. 73 if (this->getDestructorGuardCount() != 0) { 74 abort(); 75 } 76 // Invoke destroy. This is necessary since our base class may have 77 // implemented custom behavior in destroy(). 78 this->destroy(); 79 } 80 onDelayedDestroy(bool delayed)81 void onDelayedDestroy(bool delayed) override { 82 if (delayed && !this->TDD::getDestroyPending()) { 83 return; 84 } 85 // Do nothing. This will always be invoked from the call to destroy 86 // inside our destructor. 87 assert(!delayed); 88 // prevent unused variable warnings when asserts are compiled out. 89 (void)delayed; 90 } 91 92 protected: 93 /** 94 * Override our parent's destroy() method to make it protected. 95 * Callers should use the normal destructor instead of destroy 96 */ destroy()97 void destroy() override { this->TDD::destroy(); } 98 99 private: 100 // Forbidden copy constructor and assignment operator 101 UndelayedDestruction(UndelayedDestruction const&) = delete; 102 UndelayedDestruction& operator=(UndelayedDestruction const&) = delete; 103 }; 104 105 } // namespace folly 106