#pragma once #include "intrusive_ptr.h" #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// /*! * \defgroup yt_new New safe smart pointer constructors * \ingroup yt_new * * This is collection of safe smart pointer constructors. * * \page yt_new_rationale Rationale * New function family was designed to prevent the following problem. * Consider the following piece of code. * * \code * class TFoo * : public virtual TRefCounted * { * public: * TFoo(); * }; * * using TFooPtr = TIntrusivePtr; * * void RegisterObject(TFooPtr foo) * { * ... * } * * TFoo::TFoo() * { * // ... do something before * RegisterObject(this); * // ... do something after * } * \endcode * * What will happen on new TFoo() construction? After memory allocation * the reference counter for newly created instance would be initialized to zero. * Afterwards, the control goes to TFoo constructor. To invoke * RegisterObject a new temporary smart pointer to the current instance * have to be created effectively incrementing the reference counter (now one). * After RegisterObject returns the control to the constructor * the temporary pointer is destroyed effectively decrementing the reference * counter to zero hence triggering object destruction during its initialization. * * To avoid this undefined behavior New was introduced. * New holds a fake * reference to the object during its construction effectively preventing * premature destruction. * * \note An initialization like TIntrusivePtr<T> p = new T() * would result in a dangling reference due to internals of #New and * #TRefCountedBase. */ //////////////////////////////////////////////////////////////////////////////// template struct THasAllocator { using TFalse = void; }; template struct THasAllocator> { using TTrue = void; }; //////////////////////////////////////////////////////////////////////////////// //! Allocates a new instance of |T| using the standard allocator. //! Aborts the process on out-of-memory condition. template ::TFalse> TIntrusivePtr New(As&&... args); //! Allocates a new instance of |T| using a custom #allocator. //! Returns null on allocation failure. template ::TTrue> TIntrusivePtr TryNew(typename T::TAllocator* allocator, As&&... args); //! Same as #TryNewWit but aborts on allocation failure. template ::TTrue> TIntrusivePtr New(typename T::TAllocator* allocator, As&&... args); //! Allocates an instance of |T| //! Aborts the process on out-of-memory condition. template ::TFalse> TIntrusivePtr NewWithExtraSpace(size_t extraSpaceSize, As&&... args); //! Allocates a new instance of |T| with additional storage of #extraSpaceSize bytes //! using a custom #allocator. //! Returns null on allocation failure. template ::TTrue> TIntrusivePtr TryNewWithExtraSpace(typename T::TAllocator* allocator, size_t extraSpaceSize, As&&... args); //! Same as #TryNewWithExtraSpace but aborts on allocation failure. template ::TTrue> TIntrusivePtr NewWithExtraSpace(typename T::TAllocator* allocator, size_t extraSpaceSize, As&&... args); //! Allocates a new instance of |T| with a custom #deleter. //! Aborts the process on out-of-memory condition. template TIntrusivePtr NewWithDeleter(TDeleter deleter, As&&... args); //! Allocates a new instance of |T|. //! The allocation is additionally marked with #location. //! Aborts the process on out-of-memory condition. template TIntrusivePtr NewWithLocation(const TSourceLocation& location, As&&... args); //! Enables calling #New and co for types with private ctors. #define DECLARE_NEW_FRIEND() \ template \ friend struct NYT::TRefCountedWrapper; //////////////////////////////////////////////////////////////////////////////// //! CRTP mixin enabling access to instance's extra space. template class TWithExtraSpace { protected: const void* GetExtraSpacePtr() const; void* GetExtraSpacePtr(); size_t GetUsableSpaceSize() const; }; //////////////////////////////////////////////////////////////////////////////// } // namespace NYT #define NEW_INL_H_ #include "new-inl.h" #undef NEW_INL_H_