Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
SharedPointerTesting.inl
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5
6/** Toggle this define to enable shared pointer testing features */
7#define WITH_SHARED_POINTER_TESTS 0 && !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
8
10
11enum class ESPMode : uint8;
12template<typename KeyType,typename ValueType,typename SetAllocator ,typename KeyFuncs > class TMap;
13
14/**
15 * Shared pointer testing suite
16 */
17namespace SharedPointerTesting
18{
19 /**
20 * Executes various shared pointer tests. Note that some tests may require the programmer to enable
21 * some #ifdef statements to verify that code that is not expected to compile in fact does not.
22 */
23 template< ESPMode Mode > // Used to test *with* and *without* thread-safety features
24 static void TestSharedPointer()
25 {
26 {
27 // Empty shared ptr, not valid to deference
28 TSharedPtr< bool, Mode > MyEmptyBoolPtr;
29
30 // Test validity check
31 check( !MyEmptyBoolPtr.IsValid() );
32
33 // Test access to raw pointer
34 if( MyEmptyBoolPtr.Get() == nullptr )
35 {
36 // ...
37 }
38 }
39
40 {
41 // Construct owned shared pointer from object instance
42 TSharedPtr< int32, Mode > MyIntSharedPtr( new int32( 123 ) );
43
44 // Test validity check
45 check( MyIntSharedPtr.IsValid() );
46
47 // Check uniqueness
48 check( MyIntSharedPtr.IsUnique() );
49
50 // Test dereference operator
51 const int32 DeferenceTest = *MyIntSharedPtr;
52
53 // Test reference count zero destructing owned object
54 MyIntSharedPtr.Reset();
55
56
57 // Check number of references
58 check( MyIntSharedPtr.GetSharedReferenceCount() == 0 );
59
60 // MyIntSharedPtr goes out of scope, but object already deleted, nothing to do
61 }
62
63 {
64 // Test implicit conversion (not currently allowed because constructor is explicit!)
65#if 0
66 TSharedPtr< double, Mode > MyBool = 45.0;
67#endif
68 }
69
70 {
71 // Test copying shared reference
72 TSharedPtr< bool, Mode > FirstBoolRef( new bool( false ) );
73 TSharedPtr< bool, Mode > SecondBoolRef( FirstBoolRef );
74 }
75
76 {
77 // Test copying shared reference using = operator
78 TSharedPtr< bool, Mode > FirstBoolRef( new bool( false ) );
79 TSharedPtr< bool, Mode > SecondBoolRef = FirstBoolRef;
80 }
81
82 {
83 // Test arrow operator
84 struct FSharedTest
85 {
86 bool bFoo;
87 };
88 TSharedPtr< FSharedTest, Mode > SharedArray( new FSharedTest() );
89 SharedArray->bFoo = true;
90
91 // Test dereference operator
92 ( *SharedArray ).bFoo = false;
93
94 // Create an additional reference to an existing shared pointer
95 TSharedPtr< FSharedTest, Mode > OtherSharedArrayReference( SharedArray );
96
97 // Release original reference (object should not be destroyed)
98 SharedArray.Reset();
99
100 // NOTE: OtherSharedArrayReference goes out of scope here (object is destroyed)
101 }
102
103 {
104 // Test casting
105 class FBase
106 {
107 bool bFoo;
108 };
109 class FDerived
110 : public FBase
111 { };
112
113 {
114 // Explicit downcast to derived shared ptr
115 TSharedPtr< FBase, Mode > DerivedAsBasePtr( new FDerived() );
116 TSharedPtr< FDerived, Mode > DerivedPtr( StaticCastSharedPtr< FDerived >( DerivedAsBasePtr ) );
117 }
118
119 {
120 // Initialize base from derived (implicit upcast)
121 TSharedPtr< FDerived, Mode > DerivedPtr( new FDerived() );
122 TSharedPtr< FBase, Mode > BasePtr( DerivedPtr );
123 }
124
125 {
126 // Assign derived to base (implicit upcast)
127 TSharedPtr< FDerived, Mode > DerivedPtr( new FDerived() );
128 TSharedPtr< FBase, Mode > BasePtr = DerivedPtr;
129 }
130 }
131
132 // Create a shared pointer to nullptr. Consistent with std::shared_ptr, this results
133 // in a non-empty TSharedPtr (heap allocated reference count)
134 {
135 bool* Foo = nullptr;
136 TSharedPtr< bool, Mode > NullPtr( Foo );
137 check( !NullPtr.IsValid() );
138 }
139
140 // Simple validity test syntax
141 {
142 TSharedPtr< bool, Mode > BoolPtr( new bool( true ) );
143 check( BoolPtr.IsValid() );
144 }
145
146 // Empty weak pointer
147 {
148 TWeakPtr< bool, Mode > EmptyBoolWeakPtr;
149
150 // Pin should fail on empty weak ptr
151 check( !EmptyBoolWeakPtr.Pin().IsValid() );
152 }
153
154 // Create weak pointer from shared pointer
155 {
156 TSharedPtr< int32, Mode > SharedInt( new int32( 64 ) );
157 TWeakPtr< int32, Mode > WeakInt( SharedInt );
158
159 // Pin should succeed on this valid weak ptr
160 check( WeakInt.Pin().IsValid() );
161 }
162
163 // Create weak pointer from shared pointer (assignment)
164 {
165 TSharedPtr< int32, Mode > SharedInt( new int32( 64 ) );
166 TWeakPtr< int32, Mode > WeakInt = SharedInt;
167
168 // Pin should succeed on this valid weak ptr
169 check( WeakInt.Pin().IsValid() );
170
171 // Reset a weak pointer
172 WeakInt.Reset();
173 check( !WeakInt.Pin().IsValid() );
174 }
175
176 // Test weak pointer becoming invalid
177 {
178 TSharedPtr< int32, Mode > SharedInt( new int32( 64 ) );
179 TWeakPtr< int32, Mode > WeakInt = SharedInt;
180 SharedInt.Reset();
181 check( !WeakInt.Pin().IsValid() );
182 }
183
184 // Compare shared pointers
185 {
186 TSharedPtr< int32, Mode > SharedA( new int32( 64 ) );
187 TSharedPtr< int32, Mode > SharedB( new int32( 21 ) );
188 TSharedPtr< int32, Mode > SharedC( SharedB );
189
190 check( !( SharedA == SharedB ) );
191 check( SharedA != SharedB );
192 check( SharedB == SharedC );
193 }
194
195 // Compare weak pointers
196 {
197 TSharedPtr< int32, Mode > SharedA( new int32( 64 ) );
198 TSharedPtr< int32, Mode > SharedB( new int32( 21 ) );
199
200 TWeakPtr< int32, Mode > WeakA( SharedA );
201 TWeakPtr< int32, Mode > WeakB( SharedB );
202 TWeakPtr< int32, Mode > WeakC( SharedB );
203
204 {
205 check( !( WeakA.Pin() == WeakB.Pin() ) );
206 check( WeakA.Pin() != WeakB.Pin() );
207 check( WeakB.Pin() == WeakC.Pin() );
208 }
209
210 // NOTE: Weak pointer direct comparisons not supported (consistent with std::weak_ptr)
211#if 0 // Should not compile
212 {
213 check( !( WeakA == WeakB ) );
214 check( WeakA != WeakB );
215 check( WeakB == WeakC );
216 }
217#endif
218 }
219
220 // Test 'const'
221 {
222 TSharedPtr< const int32, Mode > IntPtr( new int32( 10 ) );
223 TSharedPtr< const float, Mode > FloatPtrA( new float( 1.0f ) );
224 TSharedPtr< const float, Mode > FloatPtrB( new float( 2.0f ) );
225
226 if( FloatPtrA == FloatPtrB )
227 {
228 }
229
230#if 0 // Won't compile as int32 is not compatible with float
231 if( FloatPtrB == IntPtr )
232 {
233 }
234#endif
235
236 // Assigning const pointers (references only, this is OK!)
237 FloatPtrA = FloatPtrB;
238
239 // Test const conversion (not allowed!)
240 TSharedPtr< float, Mode > MutableFloat( new float( 123.0f ) );
241#if 0 // Won't compile as implicit const_cast is not allowed
242 MutableFloat = FloatPtrA;
243#endif
244
245 // Test conversion from mutable to const (this is OK!)
246 FloatPtrA = MutableFloat;
247
248 if( FloatPtrB.IsValid() )
249 {
250#if 0 // Won't compile as value is const
251 *FloatPtrB = 10.0f;
252#endif
253 }
254
255 TWeakPtr< const float, Mode > ConstWeakFloat = FloatPtrA; // Preserving const
256#if 0 // Won't compile as value is const
257 *ConstWeakFloat.Pin() = 20.0f;
258#endif
259
260 // Test implicit const_cast (not allowed!)
261 TWeakPtr< float, Mode > WeakFloat;
262#if 0 // Won't compile as const cannot convert to mutable implicitly
263 WeakFloat = FloatPtrB; // NOTE: 'const' not preserved here
264#endif
265
266 // Test const cast
267 WeakFloat = ConstCastSharedPtr< float >( FloatPtrB );
268
269 *WeakFloat.Pin() = 20.0f;
270 }
271
272 // Test forward declaring a smart pointer to an incomplete type
273 {
274 TSharedPtr< struct FBarFoo, Mode > VecPtr;
275 struct FBarFoo
276 {
277 int32 Val;
278 };
279 VecPtr = TSharedPtr< FBarFoo, Mode >( new FBarFoo() );
280 VecPtr->Val = 20;
281 }
282
283 // Test Unreal non-standard extensions (expanded syntax)
284 {
285 // Initialize with nullptr
286 TSharedPtr< bool, Mode > EmptyPtr( nullptr );
287 TSharedPtr< float, Mode > FloatPtr = nullptr;
288
289 // Initialize with nullptr
290 TWeakPtr< bool, Mode > EmptyWeakPtr( nullptr );
291 TWeakPtr< float, Mode > FloatWeakPtr = nullptr;
292
293 // Reassign to nullptr directly (instead of calling Reset)
294 FloatPtr = TSharedPtr< float, Mode >( new float( 0.1f ) );
295 FloatPtr = nullptr;
296
297 // Test implicit construction helper (MakeShareable)
298 FloatPtr = MakeShareable( new float( 30.0f ) );
299 TSharedPtr< double, Mode >( MakeShareable( new double( 2.0 ) ) );
300
301 struct FFooBar
302 {
303 // Test function return value
304 TSharedPtr< float, Mode > GetFloatMember()
305 {
306 return FloatVal;
307 }
308
309 TSharedPtr< float, Mode > FloatVal;
310
311
312 // Test implicit construction on return
313 TSharedPtr< float, Mode > GetFloatValue()
314 {
315 return MakeShareable( new float( 123.0f ) );
316 }
317 };
318 }
319
320 // Test TSharedRef
321 {
322 // Empty TSharedRef is not allowed
323 {
324#if 0 // Won't compile as TSharedRef has no default constructor
325 TSharedRef< bool, Mode > EmptyRef;
326#endif
327
328#if 0 // Won't compile as TSharedRef has no implicit constructor that a pointer (including nullptr)
329 TSharedRef< bool, Mode > NullRef = nullptr;
330#endif
331
332 // TSharedRef initialized in constructor
333 {
334 TSharedRef< float, Mode > FloatRef( new float( 123.0f ) );
335 }
336
337 // Test reference access
338 {
339 TSharedRef< float, Mode > FloatRef( new float( 123.0f ) );
340
341 // Grab a C++ reference to the float object
342 const float& MyFloat = *FloatRef;
343
344 // Grab another C++ reference to the float object
345 const float& MyFloat2 = FloatRef.Get();
346 }
347
348 // Implicit conversion to TSharedRef is never allowed (use MakeShareable!)
349 {
350#if 0 // Won't compile as constructor is explicit
351 TSharedRef< float, Mode > FloatRef = new float( 123.0f );
352#endif
353 }
354
355 // Test MakeShareable with TSharedRef
356 {
357 TSharedRef< float, Mode > FloatRef = MakeShareable( new float( 123.0f ) );
358 }
359
360 // New shared ref with nullptr object pointer is not allowed! The following code will compile
361 // correctly, but will trigger a runtime assertion.
362 if( 0 )
363 {
364 // NOTE: The following code is unsafe and will trigger an assert
365 int32* NullInt = nullptr;
366 TSharedRef< int32, Mode > RefWithNullObject( NullInt );
367 }
368
369 // Implicit conversion from a TSharedRef to a TSharedPtr (always OK)
370 {
371 TSharedRef< int32, Mode > MySharedRef( new int32( 1 ) );
372 TSharedPtr< int32, Mode > MySharedPtr( MySharedRef );
373 }
374
375 // Explicit TSharedRef construction from a TSharedPtr is not allowed
376 {
377 TSharedPtr< int32, Mode > MySharedPtr( new int32( 1 ) );
378#if 0 // Won't compile as this constructor is intentionally private. Use ToSharedRef() instead!
379 TSharedRef< int32, Mode > MySharedRef( MySharedPtr );
380#endif
381 }
382
383 // Explicit TSharedRef assignment from a TSharedPtr is not allowed
384 {
385 TSharedPtr< int32, Mode > MySharedPtr( new int32( 1 ) );
386#if 0 // Won't compile as this constructor is intentionally private. Use ToSharedRef() instead!
387 TSharedRef< int32, Mode > MySharedRef = MySharedPtr;
388#endif
389 }
390
391 // Conversion from a TSharedPtr to a TSharedRef. Only safe when ( MySharedPtr.IsValid() == true )
392 {
393 TSharedPtr< int32, Mode > MySharedPtr( new int32( 1 ) );
394 TSharedRef< int32, Mode > MySharedRef( MySharedPtr.ToSharedRef() );
395 }
396
397 // Conversion from an invalid TSharedPtr to a TSharedRef. Never safe, will assert at runtime.
398 if( 0 ) // Will trigger a runtime assert as MySharedPtr.IsValid() == false
399 {
400 int32* NullInt = nullptr;
401 TSharedPtr< int32, Mode > MySharedPtr( NullInt );
402 TSharedRef< int32, Mode > MySharedRef( MySharedPtr.ToSharedRef() );
403 }
404
405 // TSharedRef reassignment. Safe as long as new object is not nullptr.
406 {
407 TSharedRef< int32, Mode > IntRef( new int32( 10 ) );
408 IntRef = TSharedRef< int32, Mode >( new int32( 20 ) );
409 }
410
411 // TSharedRef reassignment to nullptr object is not allowed (asserts at runtime)
412 if( 0 )
413 {
414 TSharedRef< int32, Mode > IntRef( new int32( 10 ) );
415 int32* NullInt = nullptr;
416 IntRef = TSharedRef< int32, Mode >( NullInt );
417 }
418
419 // Get a weak pointer from a shared ref. Always OK!
420 {
421 TSharedRef< int32, Mode > IntRef( new int32( 99 ) );
422 TWeakPtr< int32, Mode > WeakInt = IntRef;
423 if( WeakInt.IsValid() )
424 {
425 // ...
426 }
427 }
428
429 // Compare two shared refs
430 {
431 TSharedRef< int32, Mode > IntRef1( new int32( 99 ) );
432 TSharedRef< int32, Mode > IntRef2( new int32( 21 ) );
433 if( IntRef1 == IntRef2 )
434 {
435 // ...
436 }
437 if( IntRef1 != IntRef2 )
438 {
439 // ...
440 }
441 }
442
443 // Compare a shared pointer with a shared ref
444 {
445 // @todo: Use complex types, not int32 (has operator==)!!
446 TSharedRef< int32, Mode > IntRef( new int32( 21 ) );
447 TSharedPtr< int32, Mode > IntPtr( IntRef );
448
449 // Pointer is equal to reference because they point to the same valid object
450 check( IntRef == IntPtr && IntPtr == IntRef );
451 {
452 // ...
453 }
454
455 // Test not equal operator
456 check( !( IntRef != IntPtr || IntPtr != IntRef ) );
457 {
458 // ...
459 }
460
461 // Null pointer is never equal to a reference
462 TSharedPtr< int32, Mode > NullPtr;
463 check( !( IntRef == NullPtr ) && ( IntRef != NullPtr ) );
464 {
465 // ...
466 }
467 }
468 }
469 }
470
471 // SharedFromThis
472 {
473 class FMyClass
474 : public TSharedFromThis< FMyClass, Mode >
475 {
476 public:
477 TSharedRef< FMyClass, Mode > GetSelfAsShared()
478 {
479 return AsShared();
480 }
481 };
482
483 // Grab shared pointer to stack-allocated class, before ever assigning it to
484 // a shared pointer reference. This will trigger an assertion!
485 if( 0 )
486 {
487 FMyClass MyClass;
488 TSharedRef< FMyClass, Mode > TheClassPtr( MyClass.GetSelfAsShared() );
489 }
490
491 TSharedPtr< FMyClass, Mode > TheClassPtr1( new FMyClass() );
492 {
493 FMyClass* MyClass = TheClassPtr1.Get();
494 TSharedRef< FMyClass, Mode > TheClassPtr2( MyClass->GetSelfAsShared() );
495 }
496 }
497
498 // Hash tables
499 {
500 TSharedRef< int32, Mode > FooRef( new int32( 1 ) );
501 TSharedPtr< int32, Mode > FooPtr( FooRef );
502
503 // Map shared pointers to a type
504 TMap< TSharedPtr< int32, Mode >, bool > SharedPointerHash;
505 SharedPointerHash.Add( FooPtr, true );
506
507 // Map shared refs to a type
508 TMap< TSharedRef< int32, Mode >, bool > SharedRefHash;
509 SharedRefHash.Add( FooRef, true );
510 const bool Value = SharedRefHash.FindRef( FooRef );
511
512 // Map a type to shared refs
513 {
514 TMap< int32, TSharedRef< int32, Mode > > SharedRefValueHash;
515 SharedRefValueHash.Add(10, FooRef);
516 const int32* FoundKey = SharedRefValueHash.FindKey(FooRef);
517 check(FoundKey != nullptr && *FoundKey == 10);
518 }
519
520 // Maps and 'const'
521 {
522 TSharedRef< const int32, Mode > ConstFooRef( new int32( 1 ) );
523 TMap< int32, TSharedRef< const int32, Mode > > ConstSharedRefValueHash;
524 ConstSharedRefValueHash.Add( 10, ConstFooRef );
525 const int32* FoundKey = ConstSharedRefValueHash.FindKey( ConstFooRef );
526 check( FoundKey != nullptr && *FoundKey == 10 );
527 }
528 }
529 }
530}
531
532
533#endif // WITH_SHARED_POINTER_TESTS
#define WITH_SHARED_POINTER_TESTS