UndelayedDestruction.h 4.0 KB

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