diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/yt/memory/new.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yt/memory/new.h')
-rw-r--r-- | library/cpp/yt/memory/new.h | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/library/cpp/yt/memory/new.h b/library/cpp/yt/memory/new.h new file mode 100644 index 0000000000..2db45e0465 --- /dev/null +++ b/library/cpp/yt/memory/new.h @@ -0,0 +1,127 @@ +#pragma once + +#include "intrusive_ptr.h" +#include "ref_tracked.h" + +#include <library/cpp/yt/misc/source_location.h> + +#include <util/system/defaults.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +/*! + * \defgroup yt_new New<T> safe smart pointer constructors + * \ingroup yt_new + * + * This is collection of safe smart pointer constructors. + * + * \page yt_new_rationale Rationale + * New<T> function family was designed to prevent the following problem. + * Consider the following piece of code. + * + * \code + * class TFoo + * : public virtual TRefCounted + * { + * public: + * TFoo(); + * }; + * + * typedef TIntrusivePtr<TFoo> TFooPtr; + * + * void RegisterObject(TFooPtr foo) + * { + * ... + * } + * + * TFoo::TFoo() + * { + * // ... do something before + * RegisterObject(this); + * // ... do something after + * } + * \endcode + * + * What will happen on <tt>new TFoo()</tt> 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 + * <tt>RegisterObject</tt> a new temporary smart pointer to the current instance + * have to be created effectively incrementing the reference counter (now one). + * After <tt>RegisterObject</tt> 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 <tt>New<T></tt> was introduced. + * <tt>New<T></tt> holds a fake + * reference to the object during its construction effectively preventing + * premature destruction. + * + * \note An initialization like <tt>TIntrusivePtr<T> p = new T()</tt> + * would result in a dangling reference due to internals of #New<T> and + * #TRefCountedBase. + */ + +//////////////////////////////////////////////////////////////////////////////// + +template <class T, class = void> +struct THasAllocator +{ + using TFalse = void; +}; + +template <class T> +struct THasAllocator<T, std::void_t<typename T::TAllocator>> +{ + using TTrue = void; +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! Allocates a new instance of |T|. +template <class T, class... As, class = typename THasAllocator<T>::TFalse> +TIntrusivePtr<T> New(As&&... args); + +template <class T, class... As, class = typename THasAllocator<T>::TTrue> +TIntrusivePtr<T> New(typename T::TAllocator* allocator, As&&... args); + +//! Allocates an instance of |T| with additional storage of #extraSpaceSize bytes. +template <class T, class... As, class = typename THasAllocator<T>::TFalse> +TIntrusivePtr<T> NewWithExtraSpace(size_t extraSpaceSize, As&&... args); + +template <class T, class... As, class = typename THasAllocator<T>::TTrue> +TIntrusivePtr<T> NewWithExtraSpace(typename T::TAllocator* allocator, size_t extraSpaceSize, As&&... args); + +//! Allocates a new instance of |T| with user deleter. +template <class T, class TDeleter, class... As> +TIntrusivePtr<T> NewWithDelete(const TDeleter& deleter, As&&... args); + +//! Allocates a new instance of |T|. +//! The allocation is additionally marked with #location. +template <class T, class TTag, int Counter, class... As> +TIntrusivePtr<T> NewWithLocation(const TSourceLocation& location, As&&... args); + +//! Enables calling #New and co for types with private ctors. +#define DECLARE_NEW_FRIEND() \ + template <class DECLARE_NEW_FRIEND_T> \ + friend struct NYT::TRefCountedWrapper; + +//////////////////////////////////////////////////////////////////////////////// + +//! CRTP mixin enabling access to instance's extra space. +template <class T> +class TWithExtraSpace +{ +protected: + const void* GetExtraSpacePtr() const; + void* GetExtraSpacePtr(); +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define NEW_INL_H_ +#include "new-inl.h" +#undef NEW_INL_H_ |