1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#pragma once
#include "intrusive_ptr.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();
* };
*
* using TFooPtr = TIntrusivePtr<TFoo>;
*
* 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 a custom #deleter.
template <class T, class TDeleter, class... As>
TIntrusivePtr<T> NewWithDeleter(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();
size_t GetUsableSpaceSize() const;
};
////////////////////////////////////////////////////////////////////////////////
} // namespace NYT
#define NEW_INL_H_
#include "new-inl.h"
#undef NEW_INL_H_
|