new.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #pragma once
  2. #include "intrusive_ptr.h"
  3. #include <library/cpp/yt/misc/source_location.h>
  4. #include <util/system/defaults.h>
  5. namespace NYT {
  6. ////////////////////////////////////////////////////////////////////////////////
  7. /*!
  8. * \defgroup yt_new New<T> safe smart pointer constructors
  9. * \ingroup yt_new
  10. *
  11. * This is collection of safe smart pointer constructors.
  12. *
  13. * \page yt_new_rationale Rationale
  14. * New<T> function family was designed to prevent the following problem.
  15. * Consider the following piece of code.
  16. *
  17. * \code
  18. * class TFoo
  19. * : public virtual TRefCounted
  20. * {
  21. * public:
  22. * TFoo();
  23. * };
  24. *
  25. * using TFooPtr = TIntrusivePtr<TFoo>;
  26. *
  27. * void RegisterObject(TFooPtr foo)
  28. * {
  29. * ...
  30. * }
  31. *
  32. * TFoo::TFoo()
  33. * {
  34. * // ... do something before
  35. * RegisterObject(this);
  36. * // ... do something after
  37. * }
  38. * \endcode
  39. *
  40. * What will happen on <tt>new TFoo()</tt> construction? After memory allocation
  41. * the reference counter for newly created instance would be initialized to zero.
  42. * Afterwards, the control goes to TFoo constructor. To invoke
  43. * <tt>RegisterObject</tt> a new temporary smart pointer to the current instance
  44. * have to be created effectively incrementing the reference counter (now one).
  45. * After <tt>RegisterObject</tt> returns the control to the constructor
  46. * the temporary pointer is destroyed effectively decrementing the reference
  47. * counter to zero hence triggering object destruction during its initialization.
  48. *
  49. * To avoid this undefined behavior <tt>New<T></tt> was introduced.
  50. * <tt>New<T></tt> holds a fake
  51. * reference to the object during its construction effectively preventing
  52. * premature destruction.
  53. *
  54. * \note An initialization like <tt>TIntrusivePtr&lt;T&gt; p = new T()</tt>
  55. * would result in a dangling reference due to internals of #New<T> and
  56. * #TRefCountedBase.
  57. */
  58. ////////////////////////////////////////////////////////////////////////////////
  59. template <class T, class = void>
  60. struct THasAllocator
  61. {
  62. using TFalse = void;
  63. };
  64. template <class T>
  65. struct THasAllocator<T, std::void_t<typename T::TAllocator>>
  66. {
  67. using TTrue = void;
  68. };
  69. ////////////////////////////////////////////////////////////////////////////////
  70. //! Allocates a new instance of |T| using the standard allocator.
  71. //! Aborts the process on out-of-memory condition.
  72. template <class T, class... As, class = typename THasAllocator<T>::TFalse>
  73. TIntrusivePtr<T> New(As&&... args);
  74. //! Allocates a new instance of |T| using a custom #allocator.
  75. //! Returns null on allocation failure.
  76. template <class T, class... As, class = typename THasAllocator<T>::TTrue>
  77. TIntrusivePtr<T> TryNew(typename T::TAllocator* allocator, As&&... args);
  78. //! Same as #TryNewWit but aborts on allocation failure.
  79. template <class T, class... As, class = typename THasAllocator<T>::TTrue>
  80. TIntrusivePtr<T> New(typename T::TAllocator* allocator, As&&... args);
  81. //! Allocates an instance of |T|
  82. //! Aborts the process on out-of-memory condition.
  83. template <class T, class... As, class = typename THasAllocator<T>::TFalse>
  84. TIntrusivePtr<T> NewWithExtraSpace(size_t extraSpaceSize, As&&... args);
  85. //! Allocates a new instance of |T| with additional storage of #extraSpaceSize bytes
  86. //! using a custom #allocator.
  87. //! Returns null on allocation failure.
  88. template <class T, class... As, class = typename THasAllocator<T>::TTrue>
  89. TIntrusivePtr<T> TryNewWithExtraSpace(typename T::TAllocator* allocator, size_t extraSpaceSize, As&&... args);
  90. //! Same as #TryNewWithExtraSpace but aborts on allocation failure.
  91. template <class T, class... As, class = typename THasAllocator<T>::TTrue>
  92. TIntrusivePtr<T> NewWithExtraSpace(typename T::TAllocator* allocator, size_t extraSpaceSize, As&&... args);
  93. //! Allocates a new instance of |T| with a custom #deleter.
  94. //! Aborts the process on out-of-memory condition.
  95. template <class T, class TDeleter, class... As>
  96. TIntrusivePtr<T> NewWithDeleter(TDeleter deleter, As&&... args);
  97. //! Allocates a new instance of |T|.
  98. //! The allocation is additionally marked with #location.
  99. //! Aborts the process on out-of-memory condition.
  100. template <class T, class TTag, int Counter, class... As>
  101. TIntrusivePtr<T> NewWithLocation(const TSourceLocation& location, As&&... args);
  102. //! Enables calling #New and co for types with private ctors.
  103. #define DECLARE_NEW_FRIEND() \
  104. template <class DECLARE_NEW_FRIEND_T> \
  105. friend struct NYT::TRefCountedWrapper;
  106. ////////////////////////////////////////////////////////////////////////////////
  107. //! CRTP mixin enabling access to instance's extra space.
  108. template <class T>
  109. class TWithExtraSpace
  110. {
  111. protected:
  112. const void* GetExtraSpacePtr() const;
  113. void* GetExtraSpacePtr();
  114. size_t GetUsableSpaceSize() const;
  115. };
  116. ////////////////////////////////////////////////////////////////////////////////
  117. } // namespace NYT
  118. #define NEW_INL_H_
  119. #include "new-inl.h"
  120. #undef NEW_INL_H_