@@ -11,6 +11,9 @@ namespace oup {
1111template <typename T>
1212class observer_ptr ;
1313
14+ template <typename T>
15+ class enable_observer_from_this ;
16+
1417namespace details {
1518struct control_block {
1619 enum flag_elements {
@@ -106,13 +109,24 @@ class observable_unique_ptr_base {
106109 delete_and_pop_ref_ (block, ptr_deleter.data , ptr_deleter);
107110 }
108111
112+ // / Fill in the observer pointer for objects inheriting from enable_observer_from_this.
113+ void set_this_observer () noexcept {
114+ if constexpr (std::is_base_of_v<enable_observer_from_this<T>, T>) {
115+ if (ptr_deleter.data ) {
116+ ptr_deleter.data ->this_observer = *this ;
117+ }
118+ }
119+ }
120+
109121 // / Private constructor using pre-allocated control block.
110122 /* * \param ctrl The control block pointer
111123 * \param value The pointer to own
112124 * \note This is used by make_observable_unique().
113125 */
114126 observable_unique_ptr_base (control_block_type* ctrl, T* value) noexcept :
115- block (ctrl), ptr_deleter{Deleter{}, value} {}
127+ block (ctrl), ptr_deleter{Deleter{}, value} {
128+ set_this_observer ();
129+ }
116130
117131 // / Private constructor using pre-allocated control block.
118132 /* * \param ctrl The control block pointer
@@ -121,7 +135,9 @@ class observable_unique_ptr_base {
121135 * \note This is used by make_observable_sealed().
122136 */
123137 observable_unique_ptr_base (control_block_type* ctrl, T* value, Deleter del) noexcept :
124- block (ctrl), ptr_deleter{std::move (del), value} {}
138+ block (ctrl), ptr_deleter{std::move (del), value} {
139+ set_this_observer ();
140+ }
125141
126142 // Friendship is required for conversions.
127143 template <typename U>
@@ -181,6 +197,7 @@ class observable_unique_ptr_base {
181197 observable_unique_ptr_base (value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) {
182198 value.block = nullptr ;
183199 value.ptr_deleter .data = nullptr ;
200+ set_this_observer ();
184201 }
185202
186203 // / Transfer ownership by implicit casting
@@ -195,6 +212,7 @@ class observable_unique_ptr_base {
195212 observable_unique_ptr_base (value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) {
196213 value.block = nullptr ;
197214 value.ptr_deleter .data = nullptr ;
215+ set_this_observer ();
198216 }
199217
200218 // / Transfer ownership by explicit casting
@@ -209,6 +227,7 @@ class observable_unique_ptr_base {
209227 observable_unique_ptr_base (manager.block, value) {
210228 manager.block = nullptr ;
211229 manager.ptr_deleter .data = nullptr ;
230+ set_this_observer ();
212231 }
213232
214233 // / Transfer ownership by explicit casting
@@ -223,6 +242,7 @@ class observable_unique_ptr_base {
223242 observable_unique_ptr_base (manager.block, value, std::move(del)) {
224243 manager.block = nullptr ;
225244 manager.ptr_deleter .data = nullptr ;
245+ set_this_observer ();
226246 }
227247
228248 // / Transfer ownership by implicit casting
@@ -240,6 +260,7 @@ class observable_unique_ptr_base {
240260 ptr_deleter.data = value.ptr_deleter .data ;
241261 value.ptr_deleter .data = nullptr ;
242262 static_cast <Deleter&>(ptr_deleter) = std::move (static_cast <Deleter&>(value.ptr_deleter ));
263+ set_this_observer ();
243264
244265 return *this ;
245266 }
@@ -262,6 +283,7 @@ class observable_unique_ptr_base {
262283 ptr_deleter.data = value.ptr_deleter .data ;
263284 value.ptr_deleter .data = nullptr ;
264285 static_cast <Deleter&>(ptr_deleter) = std::move (static_cast <Deleter&>(ptr_deleter));
286+ set_this_observer ();
265287
266288 return *this ;
267289 }
@@ -299,6 +321,8 @@ class observable_unique_ptr_base {
299321 using std::swap;
300322 swap (block, other.block );
301323 swap (ptr_deleter, other.ptr_deleter );
324+ other.set_this_observer ();
325+ set_this_observer ();
302326 }
303327
304328 // / Replaces the managed object with a null pointer.
@@ -1169,6 +1193,64 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
11691193 return first.get () != second.get ();
11701194}
11711195
1196+ // / Enables creating an observer pointer from 'this'.
1197+ /* * If an object must be able to create an observer pointer to itself,
1198+ * without having direct access to the owner pointer (unique or sealed),
1199+ * then the object's class can inherit from enable_observer_from_this.
1200+ * This provides the observer_from_this() member function, which returns
1201+ * a new observer pointer to the object. For this mechanism to work,
1202+ * the class must inherit publicly from enable_observer_from_this,
1203+ * and the object must be owned by a unique or sealed pointer when
1204+ * calling observer_from_this(). If the latter condition is not satisfied,
1205+ * i.e., the object was allocated on the stack, or is owned by another
1206+ * type of smart pointer, then observer_from_this() will return nullptr.
1207+ */
1208+ template <typename T>
1209+ class enable_observer_from_this {
1210+ observer_ptr<T> this_observer;
1211+
1212+ // Friendship is required for assignement of the observer.
1213+ template <typename U, typename D>
1214+ friend class observable_unique_ptr_base ;
1215+
1216+ protected:
1217+ enable_observer_from_this () noexcept = default ;
1218+
1219+ enable_observer_from_this (const enable_observer_from_this&) noexcept {
1220+ // Do not copy the other object's observer, this would be an
1221+ // invalid reference.
1222+ };
1223+
1224+ enable_observer_from_this (enable_observer_from_this&&) noexcept {
1225+ // Do not move the other object's observer, this would be an
1226+ // invalid reference.
1227+ };
1228+
1229+ ~enable_observer_from_this () noexcept = default ;
1230+
1231+ public:
1232+
1233+ // / Return an observer pointer to 'this'.
1234+ /* * \return A new observer pointer pointing to 'this'.
1235+ * \note If 'this' is not owned by a unique or sealed pointer, i.e., if
1236+ * the object was allocated on the stack, or if it is owned by another
1237+ * type of smart pointer, then this function will return nullptr.
1238+ */
1239+ observer_ptr<T> observer_from_this () {
1240+ return this_observer;
1241+ }
1242+
1243+ // / Return a const observer pointer to 'this'.
1244+ /* * \return A new observer pointer pointing to 'this'.
1245+ * \note If 'this' is not owned by a unique or sealed pointer, i.e., if
1246+ * the object was allocated on the stack, or if it is owned by another
1247+ * type of smart pointer, then this function will return nullptr.
1248+ */
1249+ observer_ptr<const T> observer_from_this () const {
1250+ return this_observer;
1251+ }
1252+ };
1253+
11721254}
11731255
11741256#endif
0 commit comments