@@ -11,7 +11,11 @@ namespace oup {
11
11
template <typename T>
12
12
class observer_ptr ;
13
13
14
+ template <typename T>
15
+ class enable_observer_from_this ;
16
+
14
17
namespace details {
18
+
15
19
struct control_block {
16
20
enum flag_elements {
17
21
flag_none = 0 ,
@@ -34,6 +38,7 @@ template<typename T, typename Deleter>
34
38
struct ptr_and_deleter : Deleter {
35
39
T* data = nullptr ;
36
40
};
41
+
37
42
}
38
43
39
44
// / Simple default deleter
@@ -75,6 +80,9 @@ struct placement_delete
75
80
};
76
81
77
82
namespace details {
83
+
84
+ struct enable_observer_from_this_base {};
85
+
78
86
template <typename T, typename Deleter = oup::default_delete<T>>
79
87
class observable_unique_ptr_base {
80
88
protected:
@@ -106,6 +114,16 @@ class observable_unique_ptr_base {
106
114
delete_and_pop_ref_ (block, ptr_deleter.data , ptr_deleter);
107
115
}
108
116
117
+ // / Fill in the observer pointer for objects inheriting from enable_observer_from_this.
118
+ void set_this_observer_ () noexcept {
119
+ if constexpr (std::is_base_of_v<details::enable_observer_from_this_base, T>) {
120
+ if (ptr_deleter.data ) {
121
+ ptr_deleter.data ->this_observer .set_data_ (block, ptr_deleter.data );
122
+ ++block->refcount ;
123
+ }
124
+ }
125
+ }
126
+
109
127
// / Private constructor using pre-allocated control block.
110
128
/* * \param ctrl The control block pointer
111
129
* \param value The pointer to own
@@ -292,6 +310,10 @@ class observable_unique_ptr_base {
292
310
/* * \param other The other pointer to swap with
293
311
*/
294
312
void swap (observable_unique_ptr_base& other) noexcept {
313
+ if (&other == this ) {
314
+ return ;
315
+ }
316
+
295
317
using std::swap;
296
318
swap (block, other.block );
297
319
swap (ptr_deleter, other.ptr_deleter );
@@ -345,6 +367,7 @@ class observable_unique_ptr_base {
345
367
return ptr_deleter.data != nullptr ;
346
368
}
347
369
};
370
+
348
371
}
349
372
350
373
// / Unique-ownership smart pointer, can be observed by observer_ptr, ownership can be released.
@@ -381,21 +404,6 @@ class observable_unique_ptr :
381
404
return new control_block_type;
382
405
}
383
406
384
- static void pop_ref_ (control_block_type* block) noexcept {
385
- --block->refcount ;
386
- if (block->refcount == 0 ) {
387
- delete block;
388
- }
389
- }
390
-
391
- static void delete_and_pop_ref_ (control_block_type* block, T* data, Deleter& deleter) noexcept {
392
- deleter (data);
393
-
394
- block->set_expired ();
395
-
396
- pop_ref_ (block);
397
- }
398
-
399
407
// Friendship is required for conversions.
400
408
template <typename U>
401
409
friend class observer_ptr ;
@@ -433,7 +441,9 @@ class observable_unique_ptr :
433
441
* using make_observable_unique() instead of this constructor.
434
442
*/
435
443
explicit observable_unique_ptr (T* value) :
436
- base(value != nullptr ? allocate_block_() : nullptr, value) {}
444
+ base(value != nullptr ? allocate_block_() : nullptr, value) {
445
+ base::set_this_observer_ ();
446
+ }
437
447
438
448
// / Explicit ownership capture of a raw pointer, with customer deleter.
439
449
/* * \param value The raw pointer to take ownership of
@@ -443,7 +453,9 @@ class observable_unique_ptr :
443
453
* using make_observable_unique() instead of this constructor.
444
454
*/
445
455
explicit observable_unique_ptr (T* value, Deleter del) :
446
- base(value != nullptr ? allocate_block_() : nullptr, value, std::move(del)) {}
456
+ base(value != nullptr ? allocate_block_() : nullptr, value, std::move(del)) {
457
+ base::set_this_observer_ ();
458
+ }
447
459
448
460
// / Transfer ownership by implicit casting
449
461
/* * \param value The pointer to take ownership from
@@ -474,7 +486,9 @@ class observable_unique_ptr :
474
486
*/
475
487
template <typename U, typename D>
476
488
observable_unique_ptr (observable_unique_ptr<U,D>&& manager, T* value) noexcept :
477
- base (std::move(manager), value) {}
489
+ base (std::move(manager), value) {
490
+ base::set_this_observer_ ();
491
+ }
478
492
479
493
// / Transfer ownership by explicit casting
480
494
/* * \param manager The smart pointer to take ownership from
@@ -485,7 +499,9 @@ class observable_unique_ptr :
485
499
*/
486
500
template <typename U, typename D>
487
501
observable_unique_ptr (observable_unique_ptr<U,D>&& manager, T* value, Deleter del) noexcept :
488
- base (std::move(manager), value, del) {}
502
+ base (std::move(manager), value, del) {
503
+ base::set_this_observer_ ();
504
+ }
489
505
490
506
// / Transfer ownership by implicit casting
491
507
/* * \param value The pointer to take ownership from
@@ -544,8 +560,10 @@ class observable_unique_ptr :
544
560
// Delete the old pointer
545
561
// (this follows std::unique_ptr specs)
546
562
if (old_ptr) {
547
- delete_and_pop_ref_ (old_block, old_ptr, base::ptr_deleter);
563
+ base:: delete_and_pop_ref_ (old_block, old_ptr, base::ptr_deleter);
548
564
}
565
+
566
+ base::set_this_observer_ ();
549
567
}
550
568
551
569
// / Releases ownership of the managed object and mark observers as expired.
@@ -608,7 +626,9 @@ class observable_sealed_ptr :
608
626
* \note This is used by make_observable_sealed().
609
627
*/
610
628
observable_sealed_ptr (control_block_type* ctrl, T* value) noexcept :
611
- base (ctrl, value, oup::placement_delete<T>{}) {}
629
+ base (ctrl, value, oup::placement_delete<T>{}) {
630
+ base::set_this_observer_ ();
631
+ }
612
632
613
633
// Friendship is required for conversions.
614
634
template <typename U>
@@ -744,7 +764,7 @@ observable_sealed_ptr<T> make_observable_sealed(Args&& ... args) {
744
764
// Allocate memory
745
765
constexpr std::size_t block_size = sizeof (block_type);
746
766
constexpr std::size_t object_size = sizeof (T);
747
- std::byte* buffer = new std::byte[ block_size + object_size] ;
767
+ std::byte* buffer = reinterpret_cast < std::byte*>( operator new ( block_size + object_size)) ;
748
768
749
769
try {
750
770
// Construct control block and object
@@ -756,7 +776,7 @@ observable_sealed_ptr<T> make_observable_sealed(Args&& ... args) {
756
776
} catch (...) {
757
777
// Exception thrown during object construction,
758
778
// clean up memory and let exception propagate
759
- delete[] buffer;
779
+ delete buffer;
760
780
throw ;
761
781
}
762
782
}
@@ -835,6 +855,9 @@ class observer_ptr {
835
855
// Friendship is required for conversions.
836
856
template <typename U>
837
857
friend class observer_ptr ;
858
+ // Friendship is required for enable_observer_from_this.
859
+ template <typename U, typename D>
860
+ friend class details ::observable_unique_ptr_base;
838
861
839
862
using control_block = details::control_block;
840
863
@@ -848,6 +871,15 @@ class observer_ptr {
848
871
}
849
872
}
850
873
874
+ void set_data_ (control_block* b, T* d) noexcept {
875
+ if (data) {
876
+ pop_ref_ ();
877
+ }
878
+
879
+ block = b;
880
+ data = d;
881
+ }
882
+
851
883
public:
852
884
// / Type of the pointed object
853
885
using element_type = T;
@@ -936,12 +968,8 @@ class observer_ptr {
936
968
*/
937
969
template <typename U, typename D, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
938
970
observer_ptr& operator =(const observable_unique_ptr<U,D>& owner) noexcept {
939
- if (data) {
940
- pop_ref_ ();
941
- }
971
+ set_data_ (owner.block , owner.ptr_deleter .data );
942
972
943
- block = owner.block ;
944
- data = owner.ptr_deleter .data ;
945
973
if (block) {
946
974
++block->refcount ;
947
975
}
@@ -956,12 +984,8 @@ class observer_ptr {
956
984
*/
957
985
template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
958
986
observer_ptr& operator =(const observable_sealed_ptr<U>& owner) noexcept {
959
- if (data) {
960
- pop_ref_ ();
961
- }
987
+ set_data_ (owner.block , owner.ptr_deleter .data );
962
988
963
- block = owner.block ;
964
- data = owner.ptr_deleter .data ;
965
989
if (block) {
966
990
++block->refcount ;
967
991
}
@@ -973,12 +997,12 @@ class observer_ptr {
973
997
/* * \param value The existing weak pointer to copy
974
998
*/
975
999
observer_ptr& operator =(const observer_ptr& value) noexcept {
976
- if (data ) {
977
- pop_ref_ () ;
1000
+ if (&value == this ) {
1001
+ return * this ;
978
1002
}
979
1003
980
- block = value.block ;
981
- data = value. data ;
1004
+ set_data_ (value. block , value.data ) ;
1005
+
982
1006
if (block) {
983
1007
++block->refcount ;
984
1008
}
@@ -993,12 +1017,12 @@ class observer_ptr {
993
1017
*/
994
1018
template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
995
1019
observer_ptr& operator =(const observer_ptr<U>& value) noexcept {
996
- if (data ) {
997
- pop_ref_ () ;
1020
+ if (&value == this ) {
1021
+ return * this ;
998
1022
}
999
1023
1000
- block = value.block ;
1001
- data = value. data ;
1024
+ set_data_ (value. block , value.data ) ;
1025
+
1002
1026
if (block) {
1003
1027
++block->refcount ;
1004
1028
}
@@ -1012,13 +1036,9 @@ class observer_ptr {
1012
1036
* pointer is set to null and looses ownership.
1013
1037
*/
1014
1038
observer_ptr& operator =(observer_ptr&& value) noexcept {
1015
- if (data) {
1016
- pop_ref_ ();
1017
- }
1039
+ set_data_ (value.block , value.data );
1018
1040
1019
- block = value.block ;
1020
1041
value.block = nullptr ;
1021
- data = value.data ;
1022
1042
value.data = nullptr ;
1023
1043
1024
1044
return *this ;
@@ -1033,13 +1053,9 @@ class observer_ptr {
1033
1053
*/
1034
1054
template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
1035
1055
observer_ptr& operator =(observer_ptr<U>&& value) noexcept {
1036
- if (data) {
1037
- pop_ref_ ();
1038
- }
1056
+ set_data_ (value.block , value.data );
1039
1057
1040
- block = value.block ;
1041
1058
value.block = nullptr ;
1042
- data = value.data ;
1043
1059
value.data = nullptr ;
1044
1060
1045
1061
return *this ;
@@ -1114,6 +1130,10 @@ class observer_ptr {
1114
1130
/* * \param other The other pointer to swap with
1115
1131
*/
1116
1132
void swap (observer_ptr& other) noexcept {
1133
+ if (&other == this ) {
1134
+ return ;
1135
+ }
1136
+
1117
1137
using std::swap;
1118
1138
swap (block, other.block );
1119
1139
swap (data, other.data );
@@ -1153,6 +1173,64 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
1153
1173
return first.get () != second.get ();
1154
1174
}
1155
1175
1176
+ // / Enables creating an observer pointer from 'this'.
1177
+ /* * If an object must be able to create an observer pointer to itself,
1178
+ * without having direct access to the owner pointer (unique or sealed),
1179
+ * then the object's class can inherit from enable_observer_from_this.
1180
+ * This provides the observer_from_this() member function, which returns
1181
+ * a new observer pointer to the object. For this mechanism to work,
1182
+ * the class must inherit publicly from enable_observer_from_this,
1183
+ * and the object must be owned by a unique or sealed pointer when
1184
+ * calling observer_from_this(). If the latter condition is not satisfied,
1185
+ * i.e., the object was allocated on the stack, or is owned by another
1186
+ * type of smart pointer, then observer_from_this() will return nullptr.
1187
+ */
1188
+ template <typename T>
1189
+ class enable_observer_from_this : public details ::enable_observer_from_this_base {
1190
+ mutable observer_ptr<T> this_observer;
1191
+
1192
+ // Friendship is required for assignment of the observer.
1193
+ template <typename U, typename D>
1194
+ friend class details ::observable_unique_ptr_base;
1195
+
1196
+ protected:
1197
+ enable_observer_from_this () noexcept = default ;
1198
+
1199
+ enable_observer_from_this (const enable_observer_from_this&) noexcept {
1200
+ // Do not copy the other object's observer, this would be an
1201
+ // invalid reference.
1202
+ };
1203
+
1204
+ enable_observer_from_this (enable_observer_from_this&&) noexcept {
1205
+ // Do not move the other object's observer, this would be an
1206
+ // invalid reference.
1207
+ };
1208
+
1209
+ ~enable_observer_from_this () noexcept = default ;
1210
+
1211
+ public:
1212
+
1213
+ // / Return an observer pointer to 'this'.
1214
+ /* * \return A new observer pointer pointing to 'this'.
1215
+ * \note If 'this' is not owned by a unique or sealed pointer, i.e., if
1216
+ * the object was allocated on the stack, or if it is owned by another
1217
+ * type of smart pointer, then this function will return nullptr.
1218
+ */
1219
+ observer_ptr<T> observer_from_this () {
1220
+ return this_observer;
1221
+ }
1222
+
1223
+ // / Return a const observer pointer to 'this'.
1224
+ /* * \return A new observer pointer pointing to 'this'.
1225
+ * \note If 'this' is not owned by a unique or sealed pointer, i.e., if
1226
+ * the object was allocated on the stack, or if it is owned by another
1227
+ * type of smart pointer, then this function will return nullptr.
1228
+ */
1229
+ observer_ptr<const T> observer_from_this () const {
1230
+ return this_observer;
1231
+ }
1232
+ };
1233
+
1156
1234
}
1157
1235
1158
1236
#endif
0 commit comments