UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
PimplPtr.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
7
8// Single-ownership smart pointer similar to TUniquePtr but with a few differences which make it
9// particularly useful for (but not limited to) implementing the pimpl pattern:
10//
11// https://en.cppreference.com/w/cpp/language/pimpl
12//
13// Some of the features:
14//
15// Like TUniquePtr:
16// - Unique ownership - no reference counting.
17// - Move-only, no copying by default.
18// - Has the same static footprint as a pointer.
19//
20// Like TSharedPtr:
21// - The deleter is determined at binding time and type-erased, allowing the object to be deleted without access to the definition of the type.
22// - Has additional heap footprint (but smaller than TSharedPtr).
23//
24// Unlike both:
25// - No custom deleter support.
26// - No derived->base pointer conversion support (impossible to implement in C++ in a good way with multiple inheritance, and not typically needed for pimpls).
27// - The pointed-to object must be created with its Make function - it cannot take ownership of an existing pointer.
28// - No array support.
29//
30// The main benefits of this class which make it useful for pimpls:
31// - Has single-ownership semantics.
32// - Has the same performance and footprint as a pointer to the object, and minimal overhead on construction and destruction.
33// - Can be added as a class member with a forward-declared type without having to worry about the proper definition of constructors and other special member functions.
34// - Can support deep copying, including with forward declared types
35
36
40enum class EPimplPtrMode : uint8
41{
43 NoCopy,
44
47};
48
49// Forward declaration
50template<typename T, EPimplPtrMode Mode = EPimplPtrMode::NoCopy> struct TPimplPtr;
51
52
54{
55 inline constexpr SIZE_T RequiredAlignment = 16;
56
57 template <typename T>
59
60
61 template <typename T>
62 void DeleterFunc(void* Ptr)
63 {
64 // We never pass a null pointer to this function, but the compiler emits delete code
65 // which handles nulls - we don't need this extra branching code, so assume it's not.
66 UE_ASSUME(Ptr);
67 delete (TPimplHeapObjectImpl<T>*)Ptr;
68 }
69
70 template<typename T>
71 static void* CopyFunc(void* A)
72 {
74
76
77 return &NewHeap->Val;
78 };
79
80 using FDeleteFunc = void(*)(void*);
81 using FCopyFunc = void*(*)(void*);
82
83 template <typename T>
85 {
86 enum class ENoCopyType { ConstructType };
88
89 template <typename... ArgTypes>
91 : Val(Forward<ArgTypes>(Args)...)
92 {
93 // This should never fire, unless a compiler has laid out this struct in an unexpected way
95 "Unexpected alignment of T within the pimpl object");
96 }
97
98 template <typename... ArgTypes>
100 : Copier(&CopyFunc<T>)
101 , Val(Forward<ArgTypes>(Args)...)
102 {
103 // This should never fire, unless a compiler has laid out this struct in an unexpected way
105 "Unexpected alignment of T within the pimpl object");
106 }
107
108 explicit TPimplHeapObjectImpl(void* InVal)
109 : Copier(&CopyFunc<T>)
110 , Val(*(T*)InVal)
111 {
112 }
113
114
116 FCopyFunc Copier = nullptr;
117
119 };
120
121 inline void CallDeleter(void* Ptr)
122 {
123 void* ThunkedPtr = (char*)Ptr - RequiredAlignment;
124
125 // 'noexcept' as part of a function signature is a C++17 feature, but its use here
126 // can tidy up the codegen a bit. As we're likely to build with exceptions disabled
127 // anyway, this is not something we need a well-engineered solution for right now,
128 // so it's simply left commented out until we can rely on it everywhere.
129 (*(void(**)(void*) /*noexcept*/)ThunkedPtr)(ThunkedPtr);
130 }
131
132 inline void* CallCopier(void* Ptr)
133 {
134 void* BasePtr = (char*)Ptr - RequiredAlignment;
135 void* ThunkedPtr = (char*)BasePtr + sizeof(FDeleteFunc);
136
137 return (*(FCopyFunc*)ThunkedPtr)(Ptr);
138 }
139}
140
141
142template <typename T>
144{
145private:
146 template <typename, EPimplPtrMode> friend struct TPimplPtr;
147
148 template <typename U, EPimplPtrMode M, typename... ArgTypes>
149 friend TPimplPtr<U, M> MakePimpl(ArgTypes&&... Args);
150
152 : Ptr(&Impl->Val)
153 {
154 }
155
156public:
157 TPimplPtr() = default;
158
162
164 {
165 if (Ptr)
166 {
168 }
169 }
170
171 TPimplPtr(const TPimplPtr&) = delete;
172 TPimplPtr& operator=(const TPimplPtr&) = delete;
173
174 // Movable
176 : Ptr(Other.Ptr)
177 {
178 Other.Ptr = nullptr;
179 }
180
182 {
183 if (&Other != this)
184 {
185 T* LocalPtr = this->Ptr;
186 this->Ptr = Other.Ptr;
187 Other.Ptr = nullptr;
188 if (LocalPtr)
189 {
191 }
192 }
193 return *this;
194 }
195
197 {
198 Reset();
199 return *this;
200 }
201
202 bool IsValid() const
203 {
204 return !!this->Ptr;
205 }
206
207 explicit operator bool() const
208 {
209 return !!this->Ptr;
210 }
211
212 T* operator->() const
213 {
214 return this->Ptr;
215 }
216
217 T* Get() const
218 {
219 return this->Ptr;
220 }
221
222 T& operator*() const
223 {
224 return *this->Ptr;
225 }
226
227 void Reset()
228 {
229 if (T* LocalPtr = this->Ptr)
230 {
231 this->Ptr = nullptr;
233 }
234 }
235
238
239private:
240 T* Ptr = nullptr;
241};
242
243template <typename T>
244struct TPimplPtr<T, EPimplPtrMode::DeepCopy> : private TPimplPtr<T, EPimplPtrMode::NoCopy>
245{
246private:
248
249 template <typename U, EPimplPtrMode M, typename... ArgTypes>
250 friend TPimplPtr<U, M> MakePimpl(ArgTypes&&... Args);
251
252 // Super here breaks clang
254
255public:
256 TPimplPtr() = default;
257 ~TPimplPtr() = default;
258
260 {
261 if (A.IsValid())
262 {
263 this->Ptr = (T*)UE::Core::Private::PimplPtr::CallCopier(A.Ptr);
264 }
265 }
266
268 {
269 if (&A != this)
270 {
271 if (IsValid())
272 {
273 Reset();
274 }
275
276 if (A.IsValid())
277 {
278 this->Ptr = (T*)UE::Core::Private::PimplPtr::CallCopier(A.Ptr);
279 }
280 }
281
282 return *this;
283 }
284
285 TPimplPtr(TPimplPtr&&) = default;
287
291
293 {
294 Super::operator = (A);
295 return *this;
296 }
297
298 using Super::IsValid;
299 using Super::operator bool;
300 using Super::operator ->;
301 using Super::Get;
302 using Super::operator *;
303 using Super::Reset;
304};
305
306#if !PLATFORM_COMPILER_HAS_GENERATED_COMPARISON_OPERATORS
307template <typename T, EPimplPtrMode Mode> UE_FORCEINLINE_HINT bool operator==(TYPE_OF_NULLPTR, const TPimplPtr<T, Mode>& Ptr) { return !Ptr.IsValid(); }
308template <typename T, EPimplPtrMode Mode> UE_FORCEINLINE_HINT bool operator!=(TYPE_OF_NULLPTR, const TPimplPtr<T, Mode>& Ptr) { return Ptr.IsValid(); }
309#endif
310
318template <typename T, EPimplPtrMode Mode = EPimplPtrMode::NoCopy, typename... ArgTypes>
320{
322 using FHeapConstructType = typename std::conditional<Mode == EPimplPtrMode::NoCopy, typename FHeapType::ENoCopyType,
323 typename FHeapType::EDeepCopyType>::type;
324
325 static_assert(Mode != EPimplPtrMode::DeepCopy ||
326 std::is_copy_constructible<T>::value, "T must be a copyable type, to use with EPimplPtrMode::DeepCopy");
327 static_assert(sizeof(T) > 0, "T must be a complete type");
328 static_assert(alignof(T) <= UE::Core::Private::PimplPtr::RequiredAlignment, "T cannot be aligned more than 16 bytes");
329
330 return TPimplPtr<T, Mode>(new FHeapType(FHeapConstructType::ConstructType, Forward<ArgTypes>(Args)...));
331}
332
333
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::TYPE_OF_NULLPTR TYPE_OF_NULLPTR
The type of the C++ nullptr keyword.
Definition Platform.h:1157
#define UE_ASSUME(x)
Definition Platform.h:833
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
const bool
Definition NetworkReplayStreaming.h:178
UE_FORCEINLINE_HINT bool operator==(TYPE_OF_NULLPTR, const TPimplPtr< T, Mode > &Ptr)
Definition PimplPtr.h:307
UE_FORCEINLINE_HINT bool operator!=(TYPE_OF_NULLPTR, const TPimplPtr< T, Mode > &Ptr)
Definition PimplPtr.h:308
EPimplPtrMode
Definition PimplPtr.h:41
TPimplPtr< T, Mode > MakePimpl(ArgTypes &&... Args)
Definition PimplPtr.h:319
float Val(const FString &Value)
Definition UnrealMath.cpp:3163
#define STRUCT_OFFSET(struc, member)
Definition UnrealTemplate.h:218
uint8_t uint8
Definition binka_ue_file_header.h:8
Mode
Definition AnimNode_TransitionPoseEvaluator.h:28
Definition ExpressionParserTypes.h:21
Definition PimplPtr.h:54
void(*)(void *) FDeleteFunc
Definition PimplPtr.h:80
constexpr SIZE_T RequiredAlignment
Definition PimplPtr.h:55
void * CallCopier(void *Ptr)
Definition PimplPtr.h:132
void *(*)(void *) FCopyFunc
Definition PimplPtr.h:81
void DeleterFunc(void *Ptr)
Definition PimplPtr.h:62
void CallDeleter(void *Ptr)
Definition PimplPtr.h:121
TPimplPtr & operator=(TYPE_OF_NULLPTR A)
Definition PimplPtr.h:292
TPimplPtr(const TPimplPtr &A)
Definition PimplPtr.h:259
TPimplPtr(TYPE_OF_NULLPTR)
Definition PimplPtr.h:288
TPimplPtr & operator=(TPimplPtr &&)=default
TPimplPtr & operator=(const TPimplPtr &A)
Definition PimplPtr.h:267
Definition PimplPtr.h:144
void Reset()
Definition PimplPtr.h:227
UE_FORCEINLINE_HINT bool operator==(TYPE_OF_NULLPTR)
Definition PimplPtr.h:236
T * operator->() const
Definition PimplPtr.h:212
TPimplPtr(const TPimplPtr &)=delete
T * Get() const
Definition PimplPtr.h:217
~TPimplPtr()
Definition PimplPtr.h:163
T & operator*() const
Definition PimplPtr.h:222
TPimplPtr(TYPE_OF_NULLPTR)
Definition PimplPtr.h:159
TPimplPtr & operator=(TYPE_OF_NULLPTR)
Definition PimplPtr.h:196
UE_FORCEINLINE_HINT bool operator!=(TYPE_OF_NULLPTR)
Definition PimplPtr.h:237
TPimplPtr & operator=(TPimplPtr &&Other)
Definition PimplPtr.h:181
bool IsValid() const
Definition PimplPtr.h:202
TPimplPtr & operator=(const TPimplPtr &)=delete
TPimplPtr(TPimplPtr &&Other)
Definition PimplPtr.h:175
Definition PimplPtr.h:50
TPimplHeapObjectImpl(EDeepCopyType, ArgTypes &&... Args)
Definition PimplPtr.h:99
TPimplHeapObjectImpl(ENoCopyType, ArgTypes &&... Args)
Definition PimplPtr.h:90
FDeleteFunc Deleter
Definition PimplPtr.h:115
FCopyFunc Copier
Definition PimplPtr.h:116
TPimplHeapObjectImpl(void *InVal)
Definition PimplPtr.h:108