@@ -11,7 +11,11 @@ namespace oup {
1111template <typename T>
1212class observer_ptr ;
1313
14+ template <typename T>
15+ class enable_observer_from_this ;
16+
1417namespace details {
18+
1519struct control_block {
1620 enum flag_elements {
1721 flag_none = 0 ,
@@ -34,6 +38,7 @@ template<typename T, typename Deleter>
3438struct ptr_and_deleter : Deleter {
3539 T* data = nullptr ;
3640};
41+
3742}
3843
3944// / Simple default deleter
@@ -75,6 +80,9 @@ struct placement_delete
7580};
7681
7782namespace details {
83+
84+ struct enable_observer_from_this_base {};
85+
7886template <typename T, typename Deleter = oup::default_delete<T>>
7987class observable_unique_ptr_base {
8088protected:
@@ -106,6 +114,16 @@ class observable_unique_ptr_base {
106114 delete_and_pop_ref_ (block, ptr_deleter.data , ptr_deleter);
107115 }
108116
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+
109127 // / Private constructor using pre-allocated control block.
110128 /* * \param ctrl The control block pointer
111129 * \param value The pointer to own
@@ -292,6 +310,10 @@ class observable_unique_ptr_base {
292310 /* * \param other The other pointer to swap with
293311 */
294312 void swap (observable_unique_ptr_base& other) noexcept {
313+ if (&other == this ) {
314+ return ;
315+ }
316+
295317 using std::swap;
296318 swap (block, other.block );
297319 swap (ptr_deleter, other.ptr_deleter );
@@ -345,6 +367,7 @@ class observable_unique_ptr_base {
345367 return ptr_deleter.data != nullptr ;
346368 }
347369};
370+
348371}
349372
350373// / Unique-ownership smart pointer, can be observed by observer_ptr, ownership can be released.
@@ -381,21 +404,6 @@ class observable_unique_ptr :
381404 return new control_block_type;
382405 }
383406
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-
399407 // Friendship is required for conversions.
400408 template <typename U>
401409 friend class observer_ptr ;
@@ -433,7 +441,9 @@ class observable_unique_ptr :
433441 * using make_observable_unique() instead of this constructor.
434442 */
435443 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+ }
437447
438448 // / Explicit ownership capture of a raw pointer, with customer deleter.
439449 /* * \param value The raw pointer to take ownership of
@@ -443,7 +453,9 @@ class observable_unique_ptr :
443453 * using make_observable_unique() instead of this constructor.
444454 */
445455 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+ }
447459
448460 // / Transfer ownership by implicit casting
449461 /* * \param value The pointer to take ownership from
@@ -474,7 +486,9 @@ class observable_unique_ptr :
474486 */
475487 template <typename U, typename D>
476488 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+ }
478492
479493 // / Transfer ownership by explicit casting
480494 /* * \param manager The smart pointer to take ownership from
@@ -485,7 +499,9 @@ class observable_unique_ptr :
485499 */
486500 template <typename U, typename D>
487501 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+ }
489505
490506 // / Transfer ownership by implicit casting
491507 /* * \param value The pointer to take ownership from
@@ -544,8 +560,10 @@ class observable_unique_ptr :
544560 // Delete the old pointer
545561 // (this follows std::unique_ptr specs)
546562 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);
548564 }
565+
566+ base::set_this_observer_ ();
549567 }
550568
551569 // / Releases ownership of the managed object and mark observers as expired.
@@ -608,7 +626,9 @@ class observable_sealed_ptr :
608626 * \note This is used by make_observable_sealed().
609627 */
610628 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+ }
612632
613633 // Friendship is required for conversions.
614634 template <typename U>
@@ -744,7 +764,7 @@ observable_sealed_ptr<T> make_observable_sealed(Args&& ... args) {
744764 // Allocate memory
745765 constexpr std::size_t block_size = sizeof (block_type);
746766 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)) ;
748768
749769 try {
750770 // Construct control block and object
@@ -756,7 +776,7 @@ observable_sealed_ptr<T> make_observable_sealed(Args&& ... args) {
756776 } catch (...) {
757777 // Exception thrown during object construction,
758778 // clean up memory and let exception propagate
759- delete[] buffer;
779+ delete buffer;
760780 throw ;
761781 }
762782}
@@ -835,6 +855,9 @@ class observer_ptr {
835855 // Friendship is required for conversions.
836856 template <typename U>
837857 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;
838861
839862 using control_block = details::control_block;
840863
@@ -848,6 +871,15 @@ class observer_ptr {
848871 }
849872 }
850873
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+
851883public:
852884 // / Type of the pointed object
853885 using element_type = T;
@@ -936,12 +968,8 @@ class observer_ptr {
936968 */
937969 template <typename U, typename D, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
938970 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 );
942972
943- block = owner.block ;
944- data = owner.ptr_deleter .data ;
945973 if (block) {
946974 ++block->refcount ;
947975 }
@@ -956,12 +984,8 @@ class observer_ptr {
956984 */
957985 template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
958986 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 );
962988
963- block = owner.block ;
964- data = owner.ptr_deleter .data ;
965989 if (block) {
966990 ++block->refcount ;
967991 }
@@ -973,12 +997,12 @@ class observer_ptr {
973997 /* * \param value The existing weak pointer to copy
974998 */
975999 observer_ptr& operator =(const observer_ptr& value) noexcept {
976- if (data ) {
977- pop_ref_ () ;
1000+ if (&value == this ) {
1001+ return * this ;
9781002 }
9791003
980- block = value.block ;
981- data = value. data ;
1004+ set_data_ (value. block , value.data ) ;
1005+
9821006 if (block) {
9831007 ++block->refcount ;
9841008 }
@@ -993,12 +1017,12 @@ class observer_ptr {
9931017 */
9941018 template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
9951019 observer_ptr& operator =(const observer_ptr<U>& value) noexcept {
996- if (data ) {
997- pop_ref_ () ;
1020+ if (&value == this ) {
1021+ return * this ;
9981022 }
9991023
1000- block = value.block ;
1001- data = value. data ;
1024+ set_data_ (value. block , value.data ) ;
1025+
10021026 if (block) {
10031027 ++block->refcount ;
10041028 }
@@ -1012,13 +1036,9 @@ class observer_ptr {
10121036 * pointer is set to null and looses ownership.
10131037 */
10141038 observer_ptr& operator =(observer_ptr&& value) noexcept {
1015- if (data) {
1016- pop_ref_ ();
1017- }
1039+ set_data_ (value.block , value.data );
10181040
1019- block = value.block ;
10201041 value.block = nullptr ;
1021- data = value.data ;
10221042 value.data = nullptr ;
10231043
10241044 return *this ;
@@ -1033,13 +1053,9 @@ class observer_ptr {
10331053 */
10341054 template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*, T*>>>
10351055 observer_ptr& operator =(observer_ptr<U>&& value) noexcept {
1036- if (data) {
1037- pop_ref_ ();
1038- }
1056+ set_data_ (value.block , value.data );
10391057
1040- block = value.block ;
10411058 value.block = nullptr ;
1042- data = value.data ;
10431059 value.data = nullptr ;
10441060
10451061 return *this ;
@@ -1114,6 +1130,10 @@ class observer_ptr {
11141130 /* * \param other The other pointer to swap with
11151131 */
11161132 void swap (observer_ptr& other) noexcept {
1133+ if (&other == this ) {
1134+ return ;
1135+ }
1136+
11171137 using std::swap;
11181138 swap (block, other.block );
11191139 swap (data, other.data );
@@ -1153,6 +1173,64 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
11531173 return first.get () != second.get ();
11541174}
11551175
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+
11561234}
11571235
11581236#endif
0 commit comments