2 * Copyright 2004-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <type_traits>
27 * A helper class to allow a DelayedDestruction object to be instantiated on
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.
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.
43 template <typename TDD>
44 class UndelayedDestruction : public TDD {
46 // We could just use constructor inheritance, but not all compilers
47 // support that. So, just use a forwarding constructor.
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>
57 explicit UndelayedDestruction(Args&& ...args)
58 : TDD(std::forward<Args>(args)...) {
64 * The caller is responsible for ensuring that the object is only destroyed
65 * where it is safe to do so. (i.e., when the destructor guard count is 0).
67 * The exact conditions for meeting this may be dependent upon your class
68 * semantics. Typically you are only guaranteed that it is safe to destroy
69 * the object directly from the event loop (e.g., directly from a
70 * EventBase::LoopCallback), or when the event loop is stopped.
72 ~UndelayedDestruction() override {
73 // Crash if the caller is destroying us with outstanding destructor guards.
74 if (this->getDestructorGuardCount() != 0) {
77 // Invoke destroy. This is necessary since our base class may have
78 // implemented custom behavior in destroy().
82 void onDelayedDestroy(bool delayed) override {
83 if (delayed && !this->TDD::getDestroyPending()) {
86 // Do nothing. This will always be invoked from the call to destroy
87 // inside our destructor.
89 // prevent unused variable warnings when asserts are compiled out.
95 * Override our parent's destroy() method to make it protected.
96 * Callers should use the normal destructor instead of destroy
98 void destroy() override {
103 // Forbidden copy constructor and assignment operator
104 UndelayedDestruction(UndelayedDestruction const &) = delete;
105 UndelayedDestruction& operator=(UndelayedDestruction const &) = delete;